staging/lustre: Disable InfiniBand support
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / en_netdev.c
index 8359e9e..4198e9b 100644 (file)
@@ -31,6 +31,7 @@
  *
  */
 
+#include <linux/bpf.h>
 #include <linux/etherdevice.h>
 #include <linux/tcp.h>
 #include <linux/if_vlan.h>
@@ -67,6 +68,17 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up)
                offset += priv->num_tx_rings_p_up;
        }
 
+#ifdef CONFIG_MLX4_EN_DCB
+       if (!mlx4_is_slave(priv->mdev->dev)) {
+               if (up) {
+                       priv->flags |= MLX4_EN_FLAG_DCB_ENABLED;
+               } else {
+                       priv->flags &= ~MLX4_EN_FLAG_DCB_ENABLED;
+                       priv->cee_params.dcb_cfg.pfc_state = false;
+               }
+       }
+#endif /* CONFIG_MLX4_EN_DCB */
+
        return 0;
 }
 
@@ -1201,8 +1213,8 @@ static void mlx4_en_netpoll(struct net_device *dev)
        struct mlx4_en_cq *cq;
        int i;
 
-       for (i = 0; i < priv->rx_ring_num; i++) {
-               cq = priv->rx_cq[i];
+       for (i = 0; i < priv->tx_ring_num; i++) {
+               cq = priv->tx_cq[i];
                napi_schedule(&cq->napi);
        }
 }
@@ -1510,6 +1522,24 @@ static void mlx4_en_free_affinity_hint(struct mlx4_en_priv *priv, int ring_idx)
        free_cpumask_var(priv->rx_ring[ring_idx]->affinity_mask);
 }
 
+static void mlx4_en_init_recycle_ring(struct mlx4_en_priv *priv,
+                                     int tx_ring_idx)
+{
+       struct mlx4_en_tx_ring *tx_ring = priv->tx_ring[tx_ring_idx];
+       int rr_index;
+
+       rr_index = (priv->xdp_ring_num - priv->tx_ring_num) + tx_ring_idx;
+       if (rr_index >= 0) {
+               tx_ring->free_tx_desc = mlx4_en_recycle_tx_desc;
+               tx_ring->recycle_ring = priv->rx_ring[rr_index];
+               en_dbg(DRV, priv,
+                      "Set tx_ring[%d]->recycle_ring = rx_ring[%d]\n",
+                      tx_ring_idx, rr_index);
+       } else {
+               tx_ring->recycle_ring = NULL;
+       }
+}
+
 int mlx4_en_start_port(struct net_device *dev)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
@@ -1632,6 +1662,8 @@ int mlx4_en_start_port(struct net_device *dev)
                }
                tx_ring->tx_queue = netdev_get_tx_queue(dev, i);
 
+               mlx4_en_init_recycle_ring(priv, i);
+
                /* Arm CQ for TX completions */
                mlx4_en_arm_cq(priv, cq);
 
@@ -1696,10 +1728,9 @@ int mlx4_en_start_port(struct net_device *dev)
        /* Schedule multicast task to populate multicast list */
        queue_work(mdev->workqueue, &priv->rx_mode_task);
 
-#ifdef CONFIG_MLX4_EN_VXLAN
        if (priv->mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
-               vxlan_get_rx_port(dev);
-#endif
+               udp_tunnel_get_rx_info(dev);
+
        priv->port_up = true;
        netif_tx_start_all_queues(dev);
        netif_device_attach(dev);
@@ -2177,6 +2208,11 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
                en_err(priv, "Bad MTU size:%d.\n", new_mtu);
                return -EPERM;
        }
+       if (priv->xdp_ring_num && MLX4_EN_EFF_MTU(new_mtu) > FRAG_SZ0) {
+               en_err(priv, "MTU size:%d requires frags but XDP running\n",
+                      new_mtu);
+               return -EOPNOTSUPP;
+       }
        dev->mtu = new_mtu;
 
        if (netif_running(dev)) {
@@ -2434,7 +2470,6 @@ static int mlx4_en_get_phys_port_id(struct net_device *dev,
        return 0;
 }
 
-#ifdef CONFIG_MLX4_EN_VXLAN
 static void mlx4_en_add_vxlan_offloads(struct work_struct *work)
 {
        int ret;
@@ -2484,15 +2519,19 @@ static void mlx4_en_del_vxlan_offloads(struct work_struct *work)
 }
 
 static void mlx4_en_add_vxlan_port(struct  net_device *dev,
-                                  sa_family_t sa_family, __be16 port)
+                                  struct udp_tunnel_info *ti)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
+       __be16 port = ti->port;
        __be16 current_port;
 
-       if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
+       if (ti->type != UDP_TUNNEL_TYPE_VXLAN)
+               return;
+
+       if (ti->sa_family != AF_INET)
                return;
 
-       if (sa_family == AF_INET6)
+       if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
                return;
 
        current_port = priv->vxlan_port;
@@ -2507,15 +2546,19 @@ static void mlx4_en_add_vxlan_port(struct  net_device *dev,
 }
 
 static void mlx4_en_del_vxlan_port(struct  net_device *dev,
-                                  sa_family_t sa_family, __be16 port)
+                                  struct udp_tunnel_info *ti)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
+       __be16 port = ti->port;
        __be16 current_port;
 
-       if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
+       if (ti->type != UDP_TUNNEL_TYPE_VXLAN)
                return;
 
-       if (sa_family == AF_INET6)
+       if (ti->sa_family != AF_INET)
+               return;
+
+       if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
                return;
 
        current_port = priv->vxlan_port;
@@ -2550,7 +2593,6 @@ static netdev_features_t mlx4_en_features_check(struct sk_buff *skb,
 
        return features;
 }
-#endif
 
 static int mlx4_en_set_tx_maxrate(struct net_device *dev, int queue_index, u32 maxrate)
 {
@@ -2579,6 +2621,103 @@ static int mlx4_en_set_tx_maxrate(struct net_device *dev, int queue_index, u32 m
        return err;
 }
 
+static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = priv->mdev;
+       struct bpf_prog *old_prog;
+       int xdp_ring_num;
+       int port_up = 0;
+       int err;
+       int i;
+
+       xdp_ring_num = prog ? ALIGN(priv->rx_ring_num, MLX4_EN_NUM_UP) : 0;
+
+       /* No need to reconfigure buffers when simply swapping the
+        * program for a new one.
+        */
+       if (priv->xdp_ring_num == xdp_ring_num) {
+               if (prog) {
+                       prog = bpf_prog_add(prog, priv->rx_ring_num - 1);
+                       if (IS_ERR(prog))
+                               return PTR_ERR(prog);
+               }
+               for (i = 0; i < priv->rx_ring_num; i++) {
+                       /* This xchg is paired with READ_ONCE in the fastpath */
+                       old_prog = xchg(&priv->rx_ring[i]->xdp_prog, prog);
+                       if (old_prog)
+                               bpf_prog_put(old_prog);
+               }
+               return 0;
+       }
+
+       if (priv->num_frags > 1) {
+               en_err(priv, "Cannot set XDP if MTU requires multiple frags\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (priv->tx_ring_num < xdp_ring_num + MLX4_EN_NUM_UP) {
+               en_err(priv,
+                      "Minimum %d tx channels required to run XDP\n",
+                      (xdp_ring_num + MLX4_EN_NUM_UP) / MLX4_EN_NUM_UP);
+               return -EINVAL;
+       }
+
+       if (prog) {
+               prog = bpf_prog_add(prog, priv->rx_ring_num - 1);
+               if (IS_ERR(prog))
+                       return PTR_ERR(prog);
+       }
+
+       mutex_lock(&mdev->state_lock);
+       if (priv->port_up) {
+               port_up = 1;
+               mlx4_en_stop_port(dev, 1);
+       }
+
+       priv->xdp_ring_num = xdp_ring_num;
+       netif_set_real_num_tx_queues(dev, priv->tx_ring_num -
+                                                       priv->xdp_ring_num);
+
+       for (i = 0; i < priv->rx_ring_num; i++) {
+               old_prog = xchg(&priv->rx_ring[i]->xdp_prog, prog);
+               if (old_prog)
+                       bpf_prog_put(old_prog);
+       }
+
+       if (port_up) {
+               err = mlx4_en_start_port(dev);
+               if (err) {
+                       en_err(priv, "Failed starting port %d for XDP change\n",
+                              priv->port);
+                       queue_work(mdev->workqueue, &priv->watchdog_task);
+               }
+       }
+
+       mutex_unlock(&mdev->state_lock);
+       return 0;
+}
+
+static bool mlx4_xdp_attached(struct net_device *dev)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+
+       return !!priv->xdp_ring_num;
+}
+
+static int mlx4_xdp(struct net_device *dev, struct netdev_xdp *xdp)
+{
+       switch (xdp->command) {
+       case XDP_SETUP_PROG:
+               return mlx4_xdp_set(dev, xdp->prog);
+       case XDP_QUERY_PROG:
+               xdp->prog_attached = mlx4_xdp_attached(dev);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_open               = mlx4_en_open,
        .ndo_stop               = mlx4_en_close,
@@ -2603,12 +2742,11 @@ static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
        .ndo_get_phys_port_id   = mlx4_en_get_phys_port_id,
-#ifdef CONFIG_MLX4_EN_VXLAN
-       .ndo_add_vxlan_port     = mlx4_en_add_vxlan_port,
-       .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
+       .ndo_udp_tunnel_add     = mlx4_en_add_vxlan_port,
+       .ndo_udp_tunnel_del     = mlx4_en_del_vxlan_port,
        .ndo_features_check     = mlx4_en_features_check,
-#endif
        .ndo_set_tx_maxrate     = mlx4_en_set_tx_maxrate,
+       .ndo_xdp                = mlx4_xdp,
 };
 
 static const struct net_device_ops mlx4_netdev_ops_master = {
@@ -2641,12 +2779,11 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
        .ndo_get_phys_port_id   = mlx4_en_get_phys_port_id,
-#ifdef CONFIG_MLX4_EN_VXLAN
-       .ndo_add_vxlan_port     = mlx4_en_add_vxlan_port,
-       .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
+       .ndo_udp_tunnel_add     = mlx4_en_add_vxlan_port,
+       .ndo_udp_tunnel_del     = mlx4_en_del_vxlan_port,
        .ndo_features_check     = mlx4_en_features_check,
-#endif
        .ndo_set_tx_maxrate     = mlx4_en_set_tx_maxrate,
+       .ndo_xdp                = mlx4_xdp,
 };
 
 struct mlx4_en_bond {
@@ -2911,6 +3048,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        struct mlx4_en_priv *priv;
        int i;
        int err;
+#ifdef CONFIG_MLX4_EN_DCB
+       struct tc_configuration *tc;
+#endif
 
        dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv),
                                 MAX_TX_RINGS, MAX_RX_RINGS);
@@ -2936,10 +3076,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
        INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
        INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task);
-#ifdef CONFIG_MLX4_EN_VXLAN
        INIT_WORK(&priv->vxlan_add_task, mlx4_en_add_vxlan_offloads);
        INIT_WORK(&priv->vxlan_del_task, mlx4_en_del_vxlan_offloads);
-#endif
 #ifdef CONFIG_RFS_ACCEL
        INIT_LIST_HEAD(&priv->filters);
        spin_lock_init(&priv->filters_lock);
@@ -2979,6 +3117,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        priv->msg_enable = MLX4_EN_MSG_LEVEL;
 #ifdef CONFIG_MLX4_EN_DCB
        if (!mlx4_is_slave(priv->mdev->dev)) {
+               priv->cee_params.dcbx_cap = DCB_CAP_DCBX_VER_CEE |
+                                           DCB_CAP_DCBX_HOST |
+                                           DCB_CAP_DCBX_VER_IEEE;
+               priv->flags |= MLX4_EN_DCB_ENABLED;
+               priv->cee_params.dcb_cfg.pfc_state = false;
+
+               for (i = 0; i < MLX4_EN_NUM_UP; i++) {
+                       tc = &priv->cee_params.dcb_cfg.tc_config[i];
+                       tc->dcb_pfc = pfc_disabled;
+               }
+
                if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) {
                        dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
                } else {