struct mlx4_en_mc_list *mclist, *tmp;
        u64 mcast_addr = 0;
        u8 mc_list[16] = {0};
-       int err;
+       int err = 0;
 
        mutex_lock(&mdev->state_lock);
        if (!mdev->device_up) {
                        priv->flags |= MLX4_EN_FLAG_PROMISC;
 
                        /* Enable promiscouos mode */
-                       if (!(mdev->dev->caps.flags &
-                                               MLX4_DEV_CAP_FLAG_VEP_UC_STEER))
-                               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,
+                       switch (mdev->dev->caps.steering_mode) {
+                       case MLX4_STEERING_MODE_B0:
+                               err = mlx4_unicast_promisc_add(mdev->dev,
+                                                              priv->base_qpn,
                                                               priv->port);
-                       if (err)
-                               en_err(priv, "Failed enabling "
-                                            "promiscuous mode\n");
+                               if (err)
+                                       en_err(priv, "Failed enabling unicast promiscuous mode\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 enabling multicast promiscuous mode\n");
+                                       priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
+                               }
+                               break;
+
+                       case MLX4_STEERING_MODE_A0:
+                               err = mlx4_SET_PORT_qpn_calc(mdev->dev,
+                                                            priv->port,
+                                                            priv->base_qpn,
+                                                            1);
+                               if (err)
+                                       en_err(priv, "Failed enabling promiscuous mode\n");
+                               break;
+                       }
 
                        /* Disable port multicast filter (unconditionally) */
                        err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
                                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;
-                       }
-
                        /* Disable port VLAN filter */
                        err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
                        if (err)
                priv->flags &= ~MLX4_EN_FLAG_PROMISC;
 
                /* Disable promiscouos mode */
-               if (!(mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER))
-                       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,
+               switch (mdev->dev->caps.steering_mode) {
+               case MLX4_STEERING_MODE_B0:
+                       err = mlx4_unicast_promisc_remove(mdev->dev,
+                                                         priv->base_qpn,
                                                          priv->port);
-               if (err)
-                       en_err(priv, "Failed disabling promiscuous mode\n");
+                       if (err)
+                               en_err(priv, "Failed disabling unicast promiscuous 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 promiscuous mode\n");
+                               priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+                       }
+                       break;
 
-               /* Disable Multicast promisc */
-               if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
-                       err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
-                                                           priv->port);
+               case MLX4_STEERING_MODE_A0:
+                       err = mlx4_SET_PORT_qpn_calc(mdev->dev,
+                                                    priv->port,
+                                                    priv->base_qpn, 0);
                        if (err)
-                               en_err(priv, "Failed disabling multicast promiscuous mode\n");
-                       priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+                               en_err(priv, "Failed disabling promiscuous mode\n");
+                       break;
                }
 
                /* Enable port VLAN filter */
 
                /* 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);
+                       switch (mdev->dev->caps.steering_mode) {
+                       case MLX4_STEERING_MODE_B0:
+                               err = mlx4_multicast_promisc_add(mdev->dev,
+                                                                priv->base_qpn,
+                                                                priv->port);
+                               break;
+
+                       case MLX4_STEERING_MODE_A0:
+                               break;
+                       }
                        if (err)
                                en_err(priv, "Failed entering multicast promisc mode\n");
                        priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
        } else {
                /* Disable Multicast promisc */
                if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
-                       err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
-                                                           priv->port);
+                       switch (mdev->dev->caps.steering_mode) {
+                       case MLX4_STEERING_MODE_B0:
+                               err = mlx4_multicast_promisc_remove(mdev->dev,
+                                                                   priv->base_qpn,
+                                                                   priv->port);
+                               break;
+
+                       case MLX4_STEERING_MODE_A0:
+                               break;
+                       }
                        if (err)
                                en_err(priv, "Failed disabling multicast promiscuous mode\n");
                        priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
 
        MLX4_PUT(inbox, param->mc_base,         INIT_HCA_MC_BASE_OFFSET);
        MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
        MLX4_PUT(inbox, param->log_mc_hash_sz,  INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
-       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
+       if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0)
                MLX4_PUT(inbox, (u8) (1 << 3),  INIT_HCA_UC_STEERING_OFFSET);
        MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
 
 
        dev->caps.reserved_srqs      = dev_cap->reserved_srqs;
        dev->caps.max_sq_desc_sz     = dev_cap->max_sq_desc_sz;
        dev->caps.max_rq_desc_sz     = dev_cap->max_rq_desc_sz;
-       dev->caps.num_qp_per_mgm     = mlx4_get_qp_per_mgm(dev);
        /*
         * Subtract 1 from the limit because we need to allocate a
         * spare CQE so the HCA HW can tell the difference between an
        dev->caps.max_gso_sz         = dev_cap->max_gso_sz;
        dev->caps.max_rss_tbl_sz     = dev_cap->max_rss_tbl_sz;
 
+       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER &&
+           dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) {
+               dev->caps.steering_mode = MLX4_STEERING_MODE_B0;
+       } else {
+               dev->caps.steering_mode = MLX4_STEERING_MODE_A0;
+
+               if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER ||
+                   dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
+                       mlx4_warn(dev, "Must have UC_STEER and MC_STEER flags "
+                                      "set to use B0 steering. Falling back to A0 steering mode.\n");
+       }
+       mlx4_dbg(dev, "Steering mode is: %s\n",
+                mlx4_steering_mode_str(dev->caps.steering_mode));
+       dev->caps.num_qp_per_mgm = mlx4_get_qp_per_mgm(dev);
+
        /* Sense port always allowed on supported devices for ConnectX1 and 2 */
        if (dev->pdev->device != 0x1003)
                dev->caps.flags |= MLX4_DEV_CAP_FLAG_SENSE_SUPPORT;
 
 int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
                          int block_mcast_loopback, enum mlx4_protocol prot)
 {
-       if (prot == MLX4_PROT_ETH &&
-                       !(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER))
-               return 0;
 
-       if (prot == MLX4_PROT_ETH)
-               gid[7] |= (MLX4_MC_STEER << 1);
+       switch (dev->caps.steering_mode) {
+       case MLX4_STEERING_MODE_A0:
+               if (prot == MLX4_PROT_ETH)
+                       return 0;
 
-       if (mlx4_is_mfunc(dev))
-               return mlx4_QP_ATTACH(dev, qp, gid, 1,
-                                       block_mcast_loopback, prot);
+       case MLX4_STEERING_MODE_B0:
+               if (prot == MLX4_PROT_ETH)
+                       gid[7] |= (MLX4_MC_STEER << 1);
 
-       return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback,
-                                       prot, MLX4_MC_STEER);
+               if (mlx4_is_mfunc(dev))
+                       return mlx4_QP_ATTACH(dev, qp, gid, 1,
+                                             block_mcast_loopback, prot);
+               return mlx4_qp_attach_common(dev, qp, gid,
+                                            block_mcast_loopback, prot,
+                                            MLX4_MC_STEER);
+
+       default:
+               return -EINVAL;
+       }
 }
 EXPORT_SYMBOL_GPL(mlx4_multicast_attach);
 
 int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
                          enum mlx4_protocol prot)
 {
-       if (prot == MLX4_PROT_ETH &&
-                       !(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER))
-               return 0;
+       switch (dev->caps.steering_mode) {
+       case MLX4_STEERING_MODE_A0:
+               if (prot == MLX4_PROT_ETH)
+                       return 0;
 
-       if (prot == MLX4_PROT_ETH)
-               gid[7] |= (MLX4_MC_STEER << 1);
+       case MLX4_STEERING_MODE_B0:
+               if (prot == MLX4_PROT_ETH)
+                       gid[7] |= (MLX4_MC_STEER << 1);
 
-       if (mlx4_is_mfunc(dev))
-               return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
+               if (mlx4_is_mfunc(dev))
+                       return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
+
+               return mlx4_qp_detach_common(dev, qp, gid, prot,
+                                            MLX4_MC_STEER);
 
-       return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_MC_STEER);
+       default:
+               return -EINVAL;
+       }
 }
 EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
 
                        struct mlx4_qp *qp, u8 gid[16],
                        int block_mcast_loopback, enum mlx4_protocol prot)
 {
-       if (prot == MLX4_PROT_ETH &&
-                       !(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER))
-               return 0;
-
        if (prot == MLX4_PROT_ETH)
                gid[7] |= (MLX4_UC_STEER << 1);
 
 int mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
                               u8 gid[16], enum mlx4_protocol prot)
 {
-       if (prot == MLX4_PROT_ETH &&
-                       !(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER))
-               return 0;
-
        if (prot == MLX4_PROT_ETH)
                gid[7] |= (MLX4_UC_STEER << 1);
 
 
 int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
 {
-       if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER))
-               return 0;
-
        if (mlx4_is_mfunc(dev))
                return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port);
 
 
 int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
 {
-       if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER))
-               return 0;
-
        if (mlx4_is_mfunc(dev))
                return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port);
 
 
 int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
 {
-       if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER))
-               return 0;
-
        if (mlx4_is_mfunc(dev))
                return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port);
 
 
 int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
 {
-       if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER))
-               return 0;
-
        if (mlx4_is_mfunc(dev))
                return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port);
 
 
                return err;
        }
 
-       if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER)) {
+       if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
                *qpn = info->base_qpn + index;
                return 0;
        }
                 (unsigned long long) mac);
        mlx4_unregister_mac(dev, port, mac);
 
-       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
+       if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
                entry = radix_tree_lookup(&info->mac_tree, qpn);
                if (entry) {
                        mlx4_dbg(dev, "Releasing qp: port %d, mac 0x%llx,"
        int index = qpn - info->base_qpn;
        int err = 0;
 
-       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
+       if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
                entry = radix_tree_lookup(&info->mac_tree, qpn);
                if (!entry)
                        return -EINVAL;
        u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ?
                MCAST_DIRECT : MCAST_DEFAULT;
 
-       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER  &&
-           dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER)
+       if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
                return 0;
 
        mailbox = mlx4_alloc_cmd_mailbox(dev);
 
        MLX4_MFUNC_EQE_MASK     = (MLX4_MFUNC_MAX_EQES - 1)
 };
 
+/* Driver supports 2 diffrent device methods to manage traffic steering:
+ *     - B0 steering mode - Common low level API for ib and (if supported) eth.
+ *     - A0 steering mode - Limited low level API for eth. In case of IB,
+ *                          B0 mode is in use.
+ */
+enum {
+       MLX4_STEERING_MODE_A0,
+       MLX4_STEERING_MODE_B0
+};
+
+static inline const char *mlx4_steering_mode_str(int steering_mode)
+{
+       switch (steering_mode) {
+       case MLX4_STEERING_MODE_A0:
+               return "A0 steering";
+
+       case MLX4_STEERING_MODE_B0:
+               return "B0 steering";
+       default:
+               return "Unrecognize steering mode";
+       }
+}
+
 enum {
        MLX4_DEV_CAP_FLAG_RC            = 1LL <<  0,
        MLX4_DEV_CAP_FLAG_UC            = 1LL <<  1,
        int                     num_amgms;
        int                     reserved_mcgs;
        int                     num_qp_per_mgm;
+       int                     steering_mode;
        int                     num_pds;
        int                     reserved_pds;
        int                     max_xrcds;