net/mlx5e: Replace async events spinlock with synchronize_irq()
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_main.c
index 6a3e430..38944b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2015-2016, Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
  */
 
 #include <linux/mlx5/fs.h>
+#include <net/vxlan.h>
 #include "en.h"
 #include "eswitch.h"
+#include "vxlan.h"
 
 struct mlx5e_rq_param {
        u32                        rqc[MLX5_ST_SZ_DW(rqc)];
@@ -143,9 +145,12 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
        /* Collect firts the SW counters and then HW for consistency */
        s->tso_packets          = 0;
        s->tso_bytes            = 0;
+       s->tso_inner_packets    = 0;
+       s->tso_inner_bytes      = 0;
        s->tx_queue_stopped     = 0;
        s->tx_queue_wake        = 0;
        s->tx_queue_dropped     = 0;
+       s->tx_csum_inner        = 0;
        tx_offload_none         = 0;
        s->lro_packets          = 0;
        s->lro_bytes            = 0;
@@ -166,9 +171,12 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
 
                        s->tso_packets          += sq_stats->tso_packets;
                        s->tso_bytes            += sq_stats->tso_bytes;
+                       s->tso_inner_packets    += sq_stats->tso_inner_packets;
+                       s->tso_inner_bytes      += sq_stats->tso_inner_bytes;
                        s->tx_queue_stopped     += sq_stats->stopped;
                        s->tx_queue_wake        += sq_stats->wake;
                        s->tx_queue_dropped     += sq_stats->dropped;
+                       s->tx_csum_inner        += sq_stats->csum_offload_inner;
                        tx_offload_none         += sq_stats->csum_offload_none;
                }
        }
@@ -243,7 +251,7 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
                s->tx_broadcast_bytes;
 
        /* Update calculated offload counters */
-       s->tx_csum_offload = s->tx_packets - tx_offload_none;
+       s->tx_csum_offload = s->tx_packets - tx_offload_none - s->tx_csum_inner;
        s->rx_csum_good    = s->rx_packets - s->rx_csum_none -
                               s->rx_csum_sw;
 
@@ -267,9 +275,14 @@ static void mlx5e_update_stats_work(struct work_struct *work)
        mutex_unlock(&priv->state_lock);
 }
 
-static void __mlx5e_async_event(struct mlx5e_priv *priv,
-                               enum mlx5_dev_event event)
+static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
+                             enum mlx5_dev_event event, unsigned long param)
 {
+       struct mlx5e_priv *priv = vpriv;
+
+       if (!test_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state))
+               return;
+
        switch (event) {
        case MLX5_DEV_EVENT_PORT_UP:
        case MLX5_DEV_EVENT_PORT_DOWN:
@@ -281,17 +294,6 @@ static void __mlx5e_async_event(struct mlx5e_priv *priv,
        }
 }
 
-static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
-                             enum mlx5_dev_event event, unsigned long param)
-{
-       struct mlx5e_priv *priv = vpriv;
-
-       spin_lock(&priv->async_events_spinlock);
-       if (test_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state))
-               __mlx5e_async_event(priv, event);
-       spin_unlock(&priv->async_events_spinlock);
-}
-
 static void mlx5e_enable_async_events(struct mlx5e_priv *priv)
 {
        set_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state);
@@ -299,9 +301,8 @@ static void mlx5e_enable_async_events(struct mlx5e_priv *priv)
 
 static void mlx5e_disable_async_events(struct mlx5e_priv *priv)
 {
-       spin_lock_irq(&priv->async_events_spinlock);
        clear_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state);
-       spin_unlock_irq(&priv->async_events_spinlock);
+       synchronize_irq(mlx5_get_msix_vec(priv->mdev, MLX5_EQ_VEC_ASYNC));
 }
 
 #define MLX5E_HW2SW_MTU(hwmtu) (hwmtu - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN))
@@ -1400,6 +1401,24 @@ static int mlx5e_set_dev_port_mtu(struct net_device *netdev)
        return 0;
 }
 
+static void mlx5e_netdev_set_tcs(struct net_device *netdev)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       int nch = priv->params.num_channels;
+       int ntc = priv->params.num_tc;
+       int tc;
+
+       netdev_reset_tc(netdev);
+
+       if (ntc == 1)
+               return;
+
+       netdev_set_num_tc(netdev, ntc);
+
+       for (tc = 0; tc < ntc; tc++)
+               netdev_set_tc_queue(netdev, tc, nch, tc * nch);
+}
+
 int mlx5e_open_locked(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -1408,6 +1427,8 @@ int mlx5e_open_locked(struct net_device *netdev)
 
        set_bit(MLX5E_STATE_OPENED, &priv->state);
 
+       mlx5e_netdev_set_tcs(netdev);
+
        num_txqs = priv->params.num_channels * priv->params.num_tc;
        netif_set_real_num_tx_queues(netdev, num_txqs);
        netif_set_real_num_rx_queues(netdev, priv->params.num_channels);
@@ -1602,7 +1623,7 @@ static int mlx5e_create_tis(struct mlx5e_priv *priv, int tc)
 
        memset(in, 0, sizeof(in));
 
-       MLX5_SET(tisc, tisc, prio,  tc);
+       MLX5_SET(tisc, tisc, prio, tc << 1);
        MLX5_SET(tisc, tisc, transport_domain, priv->tdn);
 
        return mlx5_core_create_tis(mdev, in, sizeof(in), &priv->tisn[tc]);
@@ -1618,7 +1639,7 @@ static int mlx5e_create_tises(struct mlx5e_priv *priv)
        int err;
        int tc;
 
-       for (tc = 0; tc < priv->params.num_tc; tc++) {
+       for (tc = 0; tc < MLX5E_MAX_NUM_TC; tc++) {
                err = mlx5e_create_tis(priv, tc);
                if (err)
                        goto err_close_tises;
@@ -1637,7 +1658,7 @@ static void mlx5e_destroy_tises(struct mlx5e_priv *priv)
 {
        int tc;
 
-       for (tc = 0; tc < priv->params.num_tc; tc++)
+       for (tc = 0; tc < MLX5E_MAX_NUM_TC; tc++)
                mlx5e_destroy_tis(priv, tc);
 }
 
@@ -1824,6 +1845,40 @@ static void mlx5e_destroy_tirs(struct mlx5e_priv *priv)
                mlx5e_destroy_tir(priv, i);
 }
 
+static int mlx5e_setup_tc(struct net_device *netdev, u8 tc)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       bool was_opened;
+       int err = 0;
+
+       if (tc && tc != MLX5E_MAX_NUM_TC)
+               return -EINVAL;
+
+       mutex_lock(&priv->state_lock);
+
+       was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
+       if (was_opened)
+               mlx5e_close_locked(priv->netdev);
+
+       priv->params.num_tc = tc ? tc : 1;
+
+       if (was_opened)
+               err = mlx5e_open_locked(priv->netdev);
+
+       mutex_unlock(&priv->state_lock);
+
+       return err;
+}
+
+static int mlx5e_ndo_setup_tc(struct net_device *dev, u32 handle,
+                             __be16 proto, struct tc_to_netdev *tc)
+{
+       if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+
+       return mlx5e_setup_tc(dev, tc->tc);
+}
+
 static struct rtnl_link_stats64 *
 mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
@@ -2024,18 +2079,116 @@ static int mlx5e_get_vf_stats(struct net_device *dev,
                                            vf_stats);
 }
 
-static struct net_device_ops mlx5e_netdev_ops = {
+static void mlx5e_add_vxlan_port(struct net_device *netdev,
+                                sa_family_t sa_family, __be16 port)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       if (!mlx5e_vxlan_allowed(priv->mdev))
+               return;
+
+       mlx5e_vxlan_add_port(priv, be16_to_cpu(port));
+}
+
+static void mlx5e_del_vxlan_port(struct net_device *netdev,
+                                sa_family_t sa_family, __be16 port)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       if (!mlx5e_vxlan_allowed(priv->mdev))
+               return;
+
+       mlx5e_vxlan_del_port(priv, be16_to_cpu(port));
+}
+
+static netdev_features_t mlx5e_vxlan_features_check(struct mlx5e_priv *priv,
+                                                   struct sk_buff *skb,
+                                                   netdev_features_t features)
+{
+       struct udphdr *udph;
+       u16 proto;
+       u16 port = 0;
+
+       switch (vlan_get_protocol(skb)) {
+       case htons(ETH_P_IP):
+               proto = ip_hdr(skb)->protocol;
+               break;
+       case htons(ETH_P_IPV6):
+               proto = ipv6_hdr(skb)->nexthdr;
+               break;
+       default:
+               goto out;
+       }
+
+       if (proto == IPPROTO_UDP) {
+               udph = udp_hdr(skb);
+               port = be16_to_cpu(udph->dest);
+       }
+
+       /* Verify if UDP port is being offloaded by HW */
+       if (port && mlx5e_vxlan_lookup_port(priv, port))
+               return features;
+
+out:
+       /* Disable CSUM and GSO if the udp dport is not offloaded by HW */
+       return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+}
+
+static netdev_features_t mlx5e_features_check(struct sk_buff *skb,
+                                             struct net_device *netdev,
+                                             netdev_features_t features)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       features = vlan_features_check(skb, features);
+       features = vxlan_features_check(skb, features);
+
+       /* Validate if the tunneled packet is being offloaded by HW */
+       if (skb->encapsulation &&
+           (features & NETIF_F_CSUM_MASK || features & NETIF_F_GSO_MASK))
+               return mlx5e_vxlan_features_check(priv, skb, features);
+
+       return features;
+}
+
+static const struct net_device_ops mlx5e_netdev_ops_basic = {
        .ndo_open                = mlx5e_open,
        .ndo_stop                = mlx5e_close,
        .ndo_start_xmit          = mlx5e_xmit,
+       .ndo_setup_tc            = mlx5e_ndo_setup_tc,
+       .ndo_select_queue        = mlx5e_select_queue,
        .ndo_get_stats64         = mlx5e_get_stats,
        .ndo_set_rx_mode         = mlx5e_set_rx_mode,
        .ndo_set_mac_address     = mlx5e_set_mac,
-       .ndo_vlan_rx_add_vid     = mlx5e_vlan_rx_add_vid,
-       .ndo_vlan_rx_kill_vid    = mlx5e_vlan_rx_kill_vid,
+       .ndo_vlan_rx_add_vid     = mlx5e_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid    = mlx5e_vlan_rx_kill_vid,
        .ndo_set_features        = mlx5e_set_features,
-       .ndo_change_mtu          = mlx5e_change_mtu,
-       .ndo_do_ioctl            = mlx5e_ioctl,
+       .ndo_change_mtu          = mlx5e_change_mtu,
+       .ndo_do_ioctl            = mlx5e_ioctl,
+};
+
+static const struct net_device_ops mlx5e_netdev_ops_sriov = {
+       .ndo_open                = mlx5e_open,
+       .ndo_stop                = mlx5e_close,
+       .ndo_start_xmit          = mlx5e_xmit,
+       .ndo_setup_tc            = mlx5e_ndo_setup_tc,
+       .ndo_select_queue        = mlx5e_select_queue,
+       .ndo_get_stats64         = mlx5e_get_stats,
+       .ndo_set_rx_mode         = mlx5e_set_rx_mode,
+       .ndo_set_mac_address     = mlx5e_set_mac,
+       .ndo_vlan_rx_add_vid     = mlx5e_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid    = mlx5e_vlan_rx_kill_vid,
+       .ndo_set_features        = mlx5e_set_features,
+       .ndo_change_mtu          = mlx5e_change_mtu,
+       .ndo_do_ioctl            = mlx5e_ioctl,
+       .ndo_add_vxlan_port      = mlx5e_add_vxlan_port,
+       .ndo_del_vxlan_port      = mlx5e_del_vxlan_port,
+       .ndo_features_check      = mlx5e_features_check,
+       .ndo_set_vf_mac          = mlx5e_set_vf_mac,
+       .ndo_set_vf_vlan         = mlx5e_set_vf_vlan,
+       .ndo_get_vf_config       = mlx5e_get_vf_config,
+       .ndo_set_vf_link_state   = mlx5e_set_vf_link_state,
+       .ndo_get_vf_stats        = mlx5e_get_vf_stats,
 };
 
 static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
@@ -2070,6 +2223,24 @@ u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev)
               2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/;
 }
 
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+static void mlx5e_ets_init(struct mlx5e_priv *priv)
+{
+       int i;
+
+       priv->params.ets.ets_cap = mlx5_max_tc(priv->mdev) + 1;
+       for (i = 0; i < priv->params.ets.ets_cap; i++) {
+               priv->params.ets.tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
+               priv->params.ets.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR;
+               priv->params.ets.prio_tc[i] = i;
+       }
+
+       /* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */
+       priv->params.ets.prio_tc[0] = 1;
+       priv->params.ets.prio_tc[1] = 0;
+}
+#endif
+
 static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
                                    struct net_device *netdev,
                                    int num_channels)
@@ -2093,7 +2264,6 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
        priv->params.min_rx_wqes           =
                MLX5E_PARAMS_DEFAULT_MIN_RX_WQES;
        priv->params.num_tc                = 1;
-       priv->params.default_vlan_prio     = 0;
        priv->params.rss_hfunc             = ETH_RSS_HASH_XOR;
 
        netdev_rss_key_fill(priv->params.toeplitz_hash_key,
@@ -2108,9 +2278,11 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
        priv->mdev                         = mdev;
        priv->netdev                       = netdev;
        priv->params.num_channels          = num_channels;
-       priv->default_vlan_prio            = priv->params.default_vlan_prio;
 
-       spin_lock_init(&priv->async_events_spinlock);
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+       mlx5e_ets_init(priv);
+#endif
+
        mutex_init(&priv->state_lock);
 
        INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work);
@@ -2137,18 +2309,15 @@ static void mlx5e_build_netdev(struct net_device *netdev)
 
        SET_NETDEV_DEV(netdev, &mdev->pdev->dev);
 
-       if (priv->params.num_tc > 1)
-               mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue;
-
        if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
-               mlx5e_netdev_ops.ndo_set_vf_mac = mlx5e_set_vf_mac;
-               mlx5e_netdev_ops.ndo_set_vf_vlan = mlx5e_set_vf_vlan;
-               mlx5e_netdev_ops.ndo_get_vf_config = mlx5e_get_vf_config;
-               mlx5e_netdev_ops.ndo_set_vf_link_state = mlx5e_set_vf_link_state;
-               mlx5e_netdev_ops.ndo_get_vf_stats = mlx5e_get_vf_stats;
+               netdev->netdev_ops = &mlx5e_netdev_ops_sriov;
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+               netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
+#endif
+       } else {
+               netdev->netdev_ops = &mlx5e_netdev_ops_basic;
        }
 
-       netdev->netdev_ops        = &mlx5e_netdev_ops;
        netdev->watchdog_timeo    = 15 * HZ;
 
        netdev->ethtool_ops       = &mlx5e_ethtool_ops;
@@ -2170,6 +2339,16 @@ static void mlx5e_build_netdev(struct net_device *netdev)
        netdev->hw_features      |= NETIF_F_HW_VLAN_CTAG_RX;
        netdev->hw_features      |= NETIF_F_HW_VLAN_CTAG_FILTER;
 
+       if (mlx5e_vxlan_allowed(mdev)) {
+               netdev->hw_features     |= NETIF_F_GSO_UDP_TUNNEL;
+               netdev->hw_enc_features |= NETIF_F_IP_CSUM;
+               netdev->hw_enc_features |= NETIF_F_RXCSUM;
+               netdev->hw_enc_features |= NETIF_F_TSO;
+               netdev->hw_enc_features |= NETIF_F_TSO6;
+               netdev->hw_enc_features |= NETIF_F_RXHASH;
+               netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
+       }
+
        netdev->features          = netdev->hw_features;
        if (!priv->params.lro_en)
                netdev->features  &= ~NETIF_F_LRO;
@@ -2216,7 +2395,9 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
        if (mlx5e_check_required_hca_cap(mdev))
                return NULL;
 
-       netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv), nch, nch);
+       netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
+                                   nch * MLX5E_MAX_NUM_TC,
+                                   nch);
        if (!netdev) {
                mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
                return NULL;
@@ -2291,12 +2472,21 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
 
        mlx5e_init_eth_addr(priv);
 
+       mlx5e_vxlan_init(priv);
+
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+       mlx5e_dcbnl_ieee_setets_core(priv, &priv->params.ets);
+#endif
+
        err = register_netdev(netdev);
        if (err) {
                mlx5_core_err(mdev, "register_netdev failed, %d\n", err);
                goto err_destroy_flow_tables;
        }
 
+       if (mlx5e_vxlan_allowed(mdev))
+               vxlan_get_rx_port(netdev);
+
        mlx5e_enable_async_events(priv);
        schedule_work(&priv->set_rx_mode_work);
 
@@ -2349,6 +2539,7 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
        mlx5e_disable_async_events(priv);
        flush_scheduled_work();
        unregister_netdev(netdev);
+       mlx5e_vxlan_cleanup(priv);
        mlx5e_destroy_flow_tables(priv);
        mlx5e_destroy_tirs(priv);
        mlx5e_destroy_rqt(priv, MLX5E_SINGLE_RQ_RQT);