]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/net/mlx4/en_netdev.c
mlx4_en: Enabling new steering
[mirror_ubuntu-artful-kernel.git] / drivers / net / mlx4 / en_netdev.c
index f6ed315b4b8921901b52023516b5cbee9b9f877a..08e680100db8e36bd8dfe16edea2d5e071c8785f 100644 (file)
@@ -156,9 +156,8 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
        mutex_lock(&mdev->state_lock);
        if (priv->port_up) {
                /* Remove old MAC and insert the new one */
-               mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
-               err = mlx4_register_mac(mdev->dev, priv->port,
-                                       priv->mac, &priv->mac_index);
+               err = mlx4_replace_mac(mdev->dev, priv->port,
+                                      priv->base_qpn, priv->mac, 0);
                if (err)
                        en_err(priv, "Failed changing HW MAC address\n");
        } else
@@ -214,6 +213,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
        struct mlx4_en_dev *mdev = priv->mdev;
        struct net_device *dev = priv->dev;
        u64 mcast_addr = 0;
+       u8 mc_list[16] = {0};
        int err;
 
        mutex_lock(&mdev->state_lock);
@@ -239,8 +239,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                        priv->flags |= MLX4_EN_FLAG_PROMISC;
 
                        /* Enable promiscouos mode */
-                       err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port,
-                                                    priv->base_qpn, 1);
+                       if (!mdev->dev->caps.vep_uc_steering)
+                               err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port,
+                                                            priv->base_qpn, 1);
+                       else
+                               err = mlx4_unicast_promisc_add(mdev->dev, priv->base_qpn,
+                                                              priv->port);
                        if (err)
                                en_err(priv, "Failed enabling "
                                             "promiscous mode\n");
@@ -252,10 +256,21 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                                en_err(priv, "Failed disabling "
                                             "multicast filter\n");
 
-                       /* Disable port VLAN filter */
-                       err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL);
-                       if (err)
-                               en_err(priv, "Failed disabling VLAN filter\n");
+                       /* Add the default qp number as multicast promisc */
+                       if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
+                               err = mlx4_multicast_promisc_add(mdev->dev, priv->base_qpn,
+                                                                priv->port);
+                               if (err)
+                                       en_err(priv, "Failed entering multicast promisc mode\n");
+                               priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
+                       }
+
+                       if (priv->vlgrp) {
+                               /* Disable port VLAN filter */
+                               err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL);
+                               if (err)
+                                       en_err(priv, "Failed disabling VLAN filter\n");
+                       }
                }
                goto out;
        }
@@ -270,11 +285,24 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                priv->flags &= ~MLX4_EN_FLAG_PROMISC;
 
                /* Disable promiscouos mode */
-               err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port,
-                                            priv->base_qpn, 0);
+               if (!mdev->dev->caps.vep_uc_steering)
+                       err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port,
+                                                    priv->base_qpn, 0);
+               else
+                       err = mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn,
+                                                         priv->port);
                if (err)
                        en_err(priv, "Failed disabling promiscous mode\n");
 
+               /* Disable Multicast promisc */
+               if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
+                       err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
+                                                           priv->port);
+                       if (err)
+                               en_err(priv, "Failed disabling multicast promiscous mode\n");
+                       priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+               }
+
                /* Enable port VLAN filter */
                err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
                if (err)
@@ -287,14 +315,38 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                                          0, MLX4_MCAST_DISABLE);
                if (err)
                        en_err(priv, "Failed disabling multicast filter\n");
+
+               /* Add the default qp number as multicast promisc */
+               if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
+                       err = mlx4_multicast_promisc_add(mdev->dev, priv->base_qpn,
+                                                        priv->port);
+                       if (err)
+                               en_err(priv, "Failed entering multicast promisc mode\n");
+                       priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
+               }
        } else {
                int i;
+               /* Disable Multicast promisc */
+               if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
+                       err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
+                                                           priv->port);
+                       if (err)
+                               en_err(priv, "Failed disabling multicast promiscous mode\n");
+                       priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+               }
 
                err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
                                          0, MLX4_MCAST_DISABLE);
                if (err)
                        en_err(priv, "Failed disabling multicast filter\n");
 
+               /* Detach our qp from all the multicast addresses */
+               for (i = 0; i < priv->mc_addrs_cnt; i++) {
+                       memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
+                       mc_list[5] = priv->port;
+                       mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
+                                             mc_list, MLX4_PROT_ETH);
+               }
                /* Flush mcast filter and init it with broadcast address */
                mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST,
                                    1, MLX4_MCAST_CONFIG);
@@ -307,6 +359,10 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                for (i = 0; i < priv->mc_addrs_cnt; i++) {
                        mcast_addr =
                              mlx4_en_mac_to_u64(priv->mc_addrs + i * ETH_ALEN);
+                       memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
+                       mc_list[5] = priv->port;
+                       mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp,
+                                             mc_list, 0, MLX4_PROT_ETH);
                        mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
                                            mcast_addr, 0, MLX4_MCAST_CONFIG);
                }
@@ -314,8 +370,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                                          0, MLX4_MCAST_ENABLE);
                if (err)
                        en_err(priv, "Failed enabling multicast filter\n");
-
-               mlx4_en_clear_list(dev);
        }
 out:
        mutex_unlock(&mdev->state_lock);
@@ -557,6 +611,7 @@ int mlx4_en_start_port(struct net_device *dev)
        int err = 0;
        int i;
        int j;
+       u8 mc_list[16] = {0};
        char name[32];
 
        if (priv->port_up) {
@@ -596,10 +651,20 @@ int mlx4_en_start_port(struct net_device *dev)
                ++rx_index;
        }
 
+       /* Set port mac number */
+       en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port);
+       err = mlx4_register_mac(mdev->dev, priv->port,
+                               priv->mac, &priv->base_qpn, 0);
+       if (err) {
+               en_err(priv, "Failed setting port mac\n");
+               goto cq_err;
+       }
+       mdev->mac_removed[priv->port] = 0;
+
        err = mlx4_en_config_rss_steer(priv);
        if (err) {
                en_err(priv, "Failed configuring rss steering\n");
-               goto cq_err;
+               goto mac_err;
        }
 
        if (mdev->dev->caps.comp_pool && !priv->tx_vector) {
@@ -661,24 +726,22 @@ int mlx4_en_start_port(struct net_device *dev)
                en_err(priv, "Failed setting default qp numbers\n");
                goto tx_err;
        }
-       /* Set port mac number */
-       en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port);
-       err = mlx4_register_mac(mdev->dev, priv->port,
-                               priv->mac, &priv->mac_index);
-       if (err) {
-               en_err(priv, "Failed setting port mac\n");
-               goto tx_err;
-       }
-       mdev->mac_removed[priv->port] = 0;
 
        /* Init port */
        en_dbg(HW, priv, "Initializing port\n");
        err = mlx4_INIT_PORT(mdev->dev, priv->port);
        if (err) {
                en_err(priv, "Failed Initializing port\n");
-               goto mac_err;
+               goto tx_err;
        }
 
+       /* Attach rx QP to bradcast address */
+       memset(&mc_list[10], 0xff, ETH_ALEN);
+       mc_list[5] = priv->port;
+       if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
+                                 0, MLX4_PROT_ETH))
+               mlx4_warn(mdev, "Failed Attaching Broadcast\n");
+
        /* Schedule multicast task to populate multicast list */
        queue_work(mdev->workqueue, &priv->mcast_task);
 
@@ -686,8 +749,6 @@ int mlx4_en_start_port(struct net_device *dev)
        netif_tx_start_all_queues(dev);
        return 0;
 
-mac_err:
-       mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
 tx_err:
        while (tx_index--) {
                mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]);
@@ -695,6 +756,8 @@ tx_err:
        }
 
        mlx4_en_release_rss_steer(priv);
+mac_err:
+       mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn);
 cq_err:
        while (rx_index--)
                mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
@@ -710,6 +773,7 @@ void mlx4_en_stop_port(struct net_device *dev)
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
        int i;
+       u8 mc_list[16] = {0};
 
        if (!priv->port_up) {
                en_dbg(DRV, priv, "stop port called while port already down\n");
@@ -724,8 +788,23 @@ void mlx4_en_stop_port(struct net_device *dev)
        /* Set port as not active */
        priv->port_up = false;
 
+       /* Detach All multicasts */
+       memset(&mc_list[10], 0xff, ETH_ALEN);
+       mc_list[5] = priv->port;
+       mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
+                             MLX4_PROT_ETH);
+       for (i = 0; i < priv->mc_addrs_cnt; i++) {
+               memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
+               mc_list[5] = priv->port;
+               mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
+                                     mc_list, MLX4_PROT_ETH);
+       }
+       mlx4_en_clear_list(dev);
+       /* Flush multicast filter */
+       mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG);
+
        /* Unregister Mac address for the port */
-       mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
+       mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn);
        mdev->mac_removed[priv->port] = 1;
 
        /* Free TX Rings */