IB/mlx4: Do IBoE GID table resets per-port
[profile/ivi/kernel-x86-ivi.git] / drivers / infiniband / hw / mlx4 / main.c
index a776aab..8e10630 100644 (file)
@@ -57,6 +57,7 @@
 #define DRV_RELDATE    "April 4, 2008"
 
 #define MLX4_IB_FLOW_MAX_PRIO 0xFFF
+#define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF
 
 MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("Mellanox ConnectX HCA InfiniBand driver");
@@ -94,21 +95,27 @@ static union ib_gid zgid;
 
 static int check_flow_steering_support(struct mlx4_dev *dev)
 {
+       int eth_num_ports = 0;
        int ib_num_ports = 0;
-       int i;
-
-       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
-               ib_num_ports++;
 
-       if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
-               if (ib_num_ports || mlx4_is_mfunc(dev)) {
-                       pr_warn("Device managed flow steering is unavailable "
-                               "for IB ports or in multifunction env.\n");
-                       return 0;
+       int dmfs = dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED;
+
+       if (dmfs) {
+               int i;
+               mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
+                       eth_num_ports++;
+               mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+                       ib_num_ports++;
+               dmfs &= (!ib_num_ports ||
+                        (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB)) &&
+                       (!eth_num_ports ||
+                        (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FS_EN));
+               if (ib_num_ports && mlx4_is_mfunc(dev)) {
+                       pr_warn("Device managed flow steering is unavailable for IB port in multifunction env.\n");
+                       dmfs = 0;
                }
-               return 1;
        }
-       return 0;
+       return dmfs;
 }
 
 static int mlx4_ib_query_device(struct ib_device *ibdev,
@@ -167,7 +174,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
                        props->device_cap_flags |= IB_DEVICE_MEM_WINDOW_TYPE_2B;
                else
                        props->device_cap_flags |= IB_DEVICE_MEM_WINDOW_TYPE_2A;
-       if (check_flow_steering_support(dev->dev))
+       if (dev->steering_support ==  MLX4_STEERING_MODE_DEVICE_MANAGED)
                props->device_cap_flags |= IB_DEVICE_MANAGED_FLOW_STEERING;
        }
 
@@ -816,6 +823,7 @@ struct mlx4_ib_steering {
 };
 
 static int parse_flow_attr(struct mlx4_dev *dev,
+                          u32 qp_num,
                           union ib_flow_spec *ib_spec,
                           struct _rule_hw *mlx4_spec)
 {
@@ -831,6 +839,14 @@ static int parse_flow_attr(struct mlx4_dev *dev,
                mlx4_spec->eth.vlan_tag = ib_spec->eth.val.vlan_tag;
                mlx4_spec->eth.vlan_tag_msk = ib_spec->eth.mask.vlan_tag;
                break;
+       case IB_FLOW_SPEC_IB:
+               type = MLX4_NET_TRANS_RULE_ID_IB;
+               mlx4_spec->ib.l3_qpn =
+                       cpu_to_be32(qp_num);
+               mlx4_spec->ib.qpn_mask =
+                       cpu_to_be32(MLX4_IB_FLOW_QPN_MASK);
+               break;
+
 
        case IB_FLOW_SPEC_IPV4:
                type = MLX4_NET_TRANS_RULE_ID_IPV4;
@@ -862,6 +878,115 @@ static int parse_flow_attr(struct mlx4_dev *dev,
        return mlx4_hw_rule_sz(dev, type);
 }
 
+struct default_rules {
+       __u32 mandatory_fields[IB_FLOW_SPEC_SUPPORT_LAYERS];
+       __u32 mandatory_not_fields[IB_FLOW_SPEC_SUPPORT_LAYERS];
+       __u32 rules_create_list[IB_FLOW_SPEC_SUPPORT_LAYERS];
+       __u8  link_layer;
+};
+static const struct default_rules default_table[] = {
+       {
+               .mandatory_fields = {IB_FLOW_SPEC_IPV4},
+               .mandatory_not_fields = {IB_FLOW_SPEC_ETH},
+               .rules_create_list = {IB_FLOW_SPEC_IB},
+               .link_layer = IB_LINK_LAYER_INFINIBAND
+       }
+};
+
+static int __mlx4_ib_default_rules_match(struct ib_qp *qp,
+                                        struct ib_flow_attr *flow_attr)
+{
+       int i, j, k;
+       void *ib_flow;
+       const struct default_rules *pdefault_rules = default_table;
+       u8 link_layer = rdma_port_get_link_layer(qp->device, flow_attr->port);
+
+       for (i = 0; i < sizeof(default_table)/sizeof(default_table[0]); i++,
+            pdefault_rules++) {
+               __u32 field_types[IB_FLOW_SPEC_SUPPORT_LAYERS];
+               memset(&field_types, 0, sizeof(field_types));
+
+               if (link_layer != pdefault_rules->link_layer)
+                       continue;
+
+               ib_flow = flow_attr + 1;
+               /* we assume the specs are sorted */
+               for (j = 0, k = 0; k < IB_FLOW_SPEC_SUPPORT_LAYERS &&
+                    j < flow_attr->num_of_specs; k++) {
+                       union ib_flow_spec *current_flow =
+                               (union ib_flow_spec *)ib_flow;
+
+                       /* same layer but different type */
+                       if (((current_flow->type & IB_FLOW_SPEC_LAYER_MASK) ==
+                            (pdefault_rules->mandatory_fields[k] &
+                             IB_FLOW_SPEC_LAYER_MASK)) &&
+                           (current_flow->type !=
+                            pdefault_rules->mandatory_fields[k]))
+                               goto out;
+
+                       /* same layer, try match next one */
+                       if (current_flow->type ==
+                           pdefault_rules->mandatory_fields[k]) {
+                               j++;
+                               ib_flow +=
+                                       ((union ib_flow_spec *)ib_flow)->size;
+                       }
+               }
+
+               ib_flow = flow_attr + 1;
+               for (j = 0; j < flow_attr->num_of_specs;
+                    j++, ib_flow += ((union ib_flow_spec *)ib_flow)->size)
+                       for (k = 0; k < IB_FLOW_SPEC_SUPPORT_LAYERS; k++)
+                               /* same layer and same type */
+                               if (((union ib_flow_spec *)ib_flow)->type ==
+                                   pdefault_rules->mandatory_not_fields[k])
+                                       goto out;
+
+               return i;
+       }
+out:
+       return -1;
+}
+
+static int __mlx4_ib_create_default_rules(
+               struct mlx4_ib_dev *mdev,
+               struct ib_qp *qp,
+               const struct default_rules *pdefault_rules,
+               struct _rule_hw *mlx4_spec) {
+       int size = 0;
+       int i;
+
+       for (i = 0; i < sizeof(pdefault_rules->rules_create_list)/
+                       sizeof(pdefault_rules->rules_create_list[0]); i++) {
+               int ret;
+               union ib_flow_spec ib_spec;
+               switch (pdefault_rules->rules_create_list[i]) {
+               case 0:
+                       /* no rule */
+                       continue;
+               case IB_FLOW_SPEC_IB:
+                       ib_spec.type = IB_FLOW_SPEC_IB;
+                       ib_spec.size = sizeof(struct ib_flow_spec_ib);
+
+                       break;
+               default:
+                       /* invalid rule */
+                       return -EINVAL;
+               }
+               /* We must put empty rule, qpn is being ignored */
+               ret = parse_flow_attr(mdev->dev, 0, &ib_spec,
+                                     mlx4_spec);
+               if (ret < 0) {
+                       pr_info("invalid parsing\n");
+                       return -EINVAL;
+               }
+
+               mlx4_spec = (void *)mlx4_spec + ret;
+               size += ret;
+       }
+       return size;
+}
+
 static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_attr,
                          int domain,
                          enum mlx4_net_trans_promisc_mode flow_type,
@@ -873,6 +998,7 @@ static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_att
        struct mlx4_ib_dev *mdev = to_mdev(qp->device);
        struct mlx4_cmd_mailbox *mailbox;
        struct mlx4_net_trans_rule_hw_ctrl *ctrl;
+       int default_flow;
 
        static const u16 __mlx4_domain[] = {
                [IB_FLOW_DOMAIN_USER] = MLX4_DOMAIN_UVERBS,
@@ -907,8 +1033,21 @@ static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_att
 
        ib_flow = flow_attr + 1;
        size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
+       /* Add default flows */
+       default_flow = __mlx4_ib_default_rules_match(qp, flow_attr);
+       if (default_flow >= 0) {
+               ret = __mlx4_ib_create_default_rules(
+                               mdev, qp, default_table + default_flow,
+                               mailbox->buf + size);
+               if (ret < 0) {
+                       mlx4_free_cmd_mailbox(mdev->dev, mailbox);
+                       return -EINVAL;
+               }
+               size += ret;
+       }
        for (i = 0; i < flow_attr->num_of_specs; i++) {
-               ret = parse_flow_attr(mdev->dev, ib_flow, mailbox->buf + size);
+               ret = parse_flow_attr(mdev->dev, qp->qp_num, ib_flow,
+                                     mailbox->buf + size);
                if (ret < 0) {
                        mlx4_free_cmd_mailbox(mdev->dev, mailbox);
                        return -EINVAL;
@@ -1218,6 +1357,21 @@ static struct device_attribute *mlx4_class_attributes[] = {
        &dev_attr_board_id
 };
 
+static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id,
+                                    struct net_device *dev)
+{
+       memcpy(eui, dev->dev_addr, 3);
+       memcpy(eui + 5, dev->dev_addr + 3, 3);
+       if (vlan_id < 0x1000) {
+               eui[3] = vlan_id >> 8;
+               eui[4] = vlan_id & 0xff;
+       } else {
+               eui[3] = 0xff;
+               eui[4] = 0xfe;
+       }
+       eui[0] ^= 2;
+}
+
 static void update_gids_task(struct work_struct *work)
 {
        struct update_gid_work *gw = container_of(work, struct update_gid_work, work);
@@ -1254,7 +1408,6 @@ static void reset_gids_task(struct work_struct *work)
        struct mlx4_cmd_mailbox *mailbox;
        union ib_gid *gids;
        int err;
-       int i;
        struct mlx4_dev *dev = gw->dev->dev;
 
        mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -1266,18 +1419,16 @@ static void reset_gids_task(struct work_struct *work)
        gids = mailbox->buf;
        memcpy(gids, gw->gids, sizeof(gw->gids));
 
-       for (i = 1; i < gw->dev->num_ports + 1; i++) {
-               if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, i) ==
-                                           IB_LINK_LAYER_ETHERNET) {
-                       err = mlx4_cmd(dev, mailbox->dma,
-                                      MLX4_SET_PORT_GID_TABLE << 8 | i,
-                                      1, MLX4_CMD_SET_PORT,
-                                      MLX4_CMD_TIME_CLASS_B,
-                                      MLX4_CMD_WRAPPED);
-                       if (err)
-                               pr_warn(KERN_WARNING
-                                       "set port %d command failed\n", i);
-               }
+       if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, gw->port) ==
+                                   IB_LINK_LAYER_ETHERNET) {
+               err = mlx4_cmd(dev, mailbox->dma,
+                              MLX4_SET_PORT_GID_TABLE << 8 | gw->port,
+                              1, MLX4_CMD_SET_PORT,
+                              MLX4_CMD_TIME_CLASS_B,
+                              MLX4_CMD_WRAPPED);
+               if (err)
+                       pr_warn(KERN_WARNING
+                               "set port %d command failed\n", gw->port);
        }
 
        mlx4_free_cmd_mailbox(dev, mailbox);
@@ -1286,7 +1437,8 @@ free:
 }
 
 static int update_gid_table(struct mlx4_ib_dev *dev, int port,
-                           union ib_gid *gid, int clear)
+                           union ib_gid *gid, int clear,
+                           int default_gid)
 {
        struct update_gid_work *work;
        int i;
@@ -1295,26 +1447,31 @@ static int update_gid_table(struct mlx4_ib_dev *dev, int port,
        int found = -1;
        int max_gids;
 
-       max_gids = dev->dev->caps.gid_table_len[port];
-       for (i = 0; i < max_gids; ++i) {
-               if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid,
-                           sizeof(*gid)))
-                       found = i;
-
-               if (clear) {
-                       if (found >= 0) {
-                               need_update = 1;
-                               dev->iboe.gid_table[port - 1][found] = zgid;
-                               break;
-                       }
-               } else {
-                       if (found >= 0)
-                               break;
-
-                       if (free < 0 &&
-                           !memcmp(&dev->iboe.gid_table[port - 1][i], &zgid,
+       if (default_gid) {
+               free = 0;
+       } else {
+               max_gids = dev->dev->caps.gid_table_len[port];
+               for (i = 1; i < max_gids; ++i) {
+                       if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid,
                                    sizeof(*gid)))
-                               free = i;
+                               found = i;
+
+                       if (clear) {
+                               if (found >= 0) {
+                                       need_update = 1;
+                                       dev->iboe.gid_table[port - 1][found] =
+                                               zgid;
+                                       break;
+                               }
+                       } else {
+                               if (found >= 0)
+                                       break;
+
+                               if (free < 0 &&
+                                   !memcmp(&dev->iboe.gid_table[port - 1][i],
+                                           &zgid, sizeof(*gid)))
+                                       free = i;
+                       }
                }
        }
 
@@ -1339,7 +1496,14 @@ static int update_gid_table(struct mlx4_ib_dev *dev, int port,
        return 0;
 }
 
-static int reset_gid_table(struct mlx4_ib_dev *dev)
+static void mlx4_make_default_gid(struct  net_device *dev, union ib_gid *gid)
+{
+       gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+       mlx4_addrconf_ifid_eui48(&gid->raw[8], 0xffff, dev);
+}
+
+
+static int reset_gid_table(struct mlx4_ib_dev *dev, u8 port)
 {
        struct update_gid_work *work;
 
@@ -1347,10 +1511,12 @@ static int reset_gid_table(struct mlx4_ib_dev *dev)
        work = kzalloc(sizeof(*work), GFP_ATOMIC);
        if (!work)
                return -ENOMEM;
-       memset(dev->iboe.gid_table, 0, sizeof(dev->iboe.gid_table));
+
+       memset(dev->iboe.gid_table[port - 1], 0, sizeof(work->gids));
        memset(work->gids, 0, sizeof(work->gids));
        INIT_WORK(&work->work, reset_gids_task);
        work->dev = dev;
+       work->port = port;
        queue_work(wq, &work->work);
        return 0;
 }
@@ -1363,6 +1529,12 @@ static int mlx4_ib_addr_event(int event, struct net_device *event_netdev,
        struct net_device *real_dev = rdma_vlan_dev_real_dev(event_netdev) ?
                                rdma_vlan_dev_real_dev(event_netdev) :
                                event_netdev;
+       union ib_gid default_gid;
+
+       mlx4_make_default_gid(real_dev, &default_gid);
+
+       if (!memcmp(gid, &default_gid, sizeof(*gid)))
+               return 0;
 
        if (event != NETDEV_DOWN && event != NETDEV_UP)
                return 0;
@@ -1381,7 +1553,7 @@ static int mlx4_ib_addr_event(int event, struct net_device *event_netdev,
                     (!netif_is_bond_master(real_dev) &&
                     (real_dev == iboe->netdevs[port - 1])))
                        update_gid_table(ibdev, port, gid,
-                                        event == NETDEV_DOWN);
+                                        event == NETDEV_DOWN, 0);
 
        spin_unlock(&iboe->lock);
        return 0;
@@ -1397,7 +1569,6 @@ static u8 mlx4_ib_get_dev_port(struct net_device *dev,
                                rdma_vlan_dev_real_dev(dev) : dev;
 
        iboe = &ibdev->iboe;
-       spin_lock(&iboe->lock);
 
        for (port = 1; port <= MLX4_MAX_PORTS; ++port)
                if ((netif_is_bond_master(real_dev) &&
@@ -1406,8 +1577,6 @@ static u8 mlx4_ib_get_dev_port(struct net_device *dev,
                     (real_dev == iboe->netdevs[port - 1])))
                        break;
 
-       spin_unlock(&iboe->lock);
-
        if ((port == 0) || (port > MLX4_MAX_PORTS))
                return 0;
        else
@@ -1430,7 +1599,7 @@ static int mlx4_ib_inet_event(struct notifier_block *this, unsigned long event,
        return NOTIFY_DONE;
 }
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
 static int mlx4_ib_inet6_event(struct notifier_block *this, unsigned long event,
                                void *ptr)
 {
@@ -1450,7 +1619,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
                                 struct mlx4_ib_dev *ibdev, u8 port)
 {
        struct in_device *in_dev;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
        struct inet6_dev *in6_dev;
        union ib_gid  *pgid;
        struct inet6_ifaddr *ifp;
@@ -1468,19 +1637,19 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
                        /*ifa->ifa_address;*/
                        ipv6_addr_set_v4mapped(ifa->ifa_address,
                                               (struct in6_addr *)&gid);
-                       update_gid_table(ibdev, port, &gid, 0);
+                       update_gid_table(ibdev, port, &gid, 0, 0);
                }
                endfor_ifa(in_dev);
                in_dev_put(in_dev);
        }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
        /* IPv6 gids */
        in6_dev = in6_dev_get(dev);
        if (in6_dev) {
                read_lock_bh(&in6_dev->lock);
                list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
                        pgid = (union ib_gid *)&ifp->addr;
-                       update_gid_table(ibdev, port, pgid, 0);
+                       update_gid_table(ibdev, port, pgid, 0, 0);
                }
                read_unlock_bh(&in6_dev->lock);
                in6_dev_put(in6_dev);
@@ -1488,14 +1657,26 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
 #endif
 }
 
+static void mlx4_ib_set_default_gid(struct mlx4_ib_dev *ibdev,
+                                struct  net_device *dev, u8 port)
+{
+       union ib_gid gid;
+       mlx4_make_default_gid(dev, &gid);
+       update_gid_table(ibdev, port, &gid, 0, 1);
+}
+
 static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev)
 {
        struct  net_device *dev;
+       struct mlx4_ib_iboe *iboe = &ibdev->iboe;
+       int i;
 
-       if (reset_gid_table(ibdev))
-               return -1;
+       for (i = 1; i <= ibdev->num_ports; ++i)
+               if (reset_gid_table(ibdev, i))
+                       return -1;
 
        read_lock(&dev_base_lock);
+       spin_lock(&iboe->lock);
 
        for_each_netdev(&init_net, dev) {
                u8 port = mlx4_ib_get_dev_port(dev, ibdev);
@@ -1503,6 +1684,7 @@ static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev)
                        mlx4_ib_get_dev_addr(dev, ibdev, port);
        }
 
+       spin_unlock(&iboe->lock);
        read_unlock(&dev_base_lock);
 
        return 0;
@@ -1521,13 +1703,13 @@ static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev)
                struct net_device *curr_master;
                iboe->netdevs[port - 1] =
                        mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port);
-
+               if (iboe->netdevs[port - 1])
+                       mlx4_ib_set_default_gid(ibdev,
+                                               iboe->netdevs[port - 1], port);
                if (iboe->netdevs[port - 1] &&
                    netif_is_bond_slave(iboe->netdevs[port - 1])) {
-                       rtnl_lock();
                        iboe->masters[port - 1] = netdev_master_upper_dev_get(
                                iboe->netdevs[port - 1]);
-                       rtnl_unlock();
                }
                curr_master = iboe->masters[port - 1];
 
@@ -1671,6 +1853,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        int i, j;
        int err;
        struct mlx4_ib_iboe *iboe;
+       int ib_num_ports = 0;
 
        pr_info_once("%s", mlx4_ib_version);
 
@@ -1820,6 +2003,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        }
 
        if (check_flow_steering_support(dev)) {
+               ibdev->steering_support = MLX4_STEERING_MODE_DEVICE_MANAGED;
                ibdev->ib_dev.create_flow       = mlx4_ib_create_flow;
                ibdev->ib_dev.destroy_flow      = mlx4_ib_destroy_flow;
 
@@ -1845,11 +2029,42 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                                ibdev->counters[i] = -1;
        }
 
+       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+               ib_num_ports++;
+
        spin_lock_init(&ibdev->sm_lock);
        mutex_init(&ibdev->cap_mask_mutex);
 
+       if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED &&
+           ib_num_ports) {
+               ibdev->steer_qpn_count = MLX4_IB_UC_MAX_NUM_QPS;
+               err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count,
+                                           MLX4_IB_UC_STEER_QPN_ALIGN,
+                                           &ibdev->steer_qpn_base);
+               if (err)
+                       goto err_counter;
+
+               ibdev->ib_uc_qpns_bitmap =
+                       kmalloc(BITS_TO_LONGS(ibdev->steer_qpn_count) *
+                               sizeof(long),
+                               GFP_KERNEL);
+               if (!ibdev->ib_uc_qpns_bitmap) {
+                       dev_err(&dev->pdev->dev, "bit map alloc failed\n");
+                       goto err_steer_qp_release;
+               }
+
+               bitmap_zero(ibdev->ib_uc_qpns_bitmap, ibdev->steer_qpn_count);
+
+               err = mlx4_FLOW_STEERING_IB_UC_QP_RANGE(
+                               dev, ibdev->steer_qpn_base,
+                               ibdev->steer_qpn_base +
+                               ibdev->steer_qpn_count - 1);
+               if (err)
+                       goto err_steer_free_bitmap;
+       }
+
        if (ib_register_device(&ibdev->ib_dev, NULL))
-               goto err_counter;
+               goto err_steer_free_bitmap;
 
        if (mlx4_ib_mad_init(ibdev))
                goto err_reg;
@@ -1874,7 +2089,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                                goto err_notif;
                        }
                }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
                if (!iboe->nb_inet6.notifier_call) {
                        iboe->nb_inet6.notifier_call = mlx4_ib_inet6_event;
                        err = register_inet6addr_notifier(&iboe->nb_inet6);
@@ -1884,7 +2099,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                        }
                }
 #endif
+               rtnl_lock();
                mlx4_ib_scan_netdevs(ibdev);
+               rtnl_unlock();
                mlx4_ib_init_gid_table(ibdev);
        }
 
@@ -1921,7 +2138,7 @@ err_notif:
                        pr_warn("failure unregistering notifier\n");
                ibdev->iboe.nb_inet.notifier_call = NULL;
        }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
        if (ibdev->iboe.nb_inet6.notifier_call) {
                if (unregister_inet6addr_notifier(&ibdev->iboe.nb_inet6))
                        pr_warn("failure unregistering notifier\n");
@@ -1938,6 +2155,13 @@ err_mad:
 err_reg:
        ib_unregister_device(&ibdev->ib_dev);
 
+err_steer_free_bitmap:
+       kfree(ibdev->ib_uc_qpns_bitmap);
+
+err_steer_qp_release:
+       if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED)
+               mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
+                                     ibdev->steer_qpn_count);
 err_counter:
        for (; i; --i)
                if (ibdev->counters[i - 1] != -1)
@@ -1958,6 +2182,69 @@ err_dealloc:
        return NULL;
 }
 
+int mlx4_ib_steer_qp_alloc(struct mlx4_ib_dev *dev, int count, int *qpn)
+{
+       int offset;
+
+       WARN_ON(!dev->ib_uc_qpns_bitmap);
+
+       offset = bitmap_find_free_region(dev->ib_uc_qpns_bitmap,
+                                        dev->steer_qpn_count,
+                                        get_count_order(count));
+       if (offset < 0)
+               return offset;
+
+       *qpn = dev->steer_qpn_base + offset;
+       return 0;
+}
+
+void mlx4_ib_steer_qp_free(struct mlx4_ib_dev *dev, u32 qpn, int count)
+{
+       if (!qpn ||
+           dev->steering_support != MLX4_STEERING_MODE_DEVICE_MANAGED)
+               return;
+
+       BUG_ON(qpn < dev->steer_qpn_base);
+
+       bitmap_release_region(dev->ib_uc_qpns_bitmap,
+                             qpn - dev->steer_qpn_base,
+                             get_count_order(count));
+}
+
+int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
+                        int is_attach)
+{
+       int err;
+       size_t flow_size;
+       struct ib_flow_attr *flow = NULL;
+       struct ib_flow_spec_ib *ib_spec;
+
+       if (is_attach) {
+               flow_size = sizeof(struct ib_flow_attr) +
+                           sizeof(struct ib_flow_spec_ib);
+               flow = kzalloc(flow_size, GFP_KERNEL);
+               if (!flow)
+                       return -ENOMEM;
+               flow->port = mqp->port;
+               flow->num_of_specs = 1;
+               flow->size = flow_size;
+               ib_spec = (struct ib_flow_spec_ib *)(flow + 1);
+               ib_spec->type = IB_FLOW_SPEC_IB;
+               ib_spec->size = sizeof(struct ib_flow_spec_ib);
+               /* Add an empty rule for IB L2 */
+               memset(&ib_spec->mask, 0, sizeof(ib_spec->mask));
+
+               err = __mlx4_ib_create_flow(&mqp->ibqp, flow,
+                                           IB_FLOW_DOMAIN_NIC,
+                                           MLX4_FS_REGULAR,
+                                           &mqp->reg_id);
+       } else {
+               err = __mlx4_ib_destroy_flow(mdev->dev, mqp->reg_id);
+       }
+       kfree(flow);
+       return err;
+}
+
 static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
 {
        struct mlx4_ib_dev *ibdev = ibdev_ptr;
@@ -1971,18 +2258,26 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
                        pr_warn("failure unregistering notifier\n");
                ibdev->iboe.nb.notifier_call = NULL;
        }
+
+       if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
+                                     ibdev->steer_qpn_count);
+               kfree(ibdev->ib_uc_qpns_bitmap);
+       }
+
        if (ibdev->iboe.nb_inet.notifier_call) {
                if (unregister_inetaddr_notifier(&ibdev->iboe.nb_inet))
                        pr_warn("failure unregistering notifier\n");
                ibdev->iboe.nb_inet.notifier_call = NULL;
        }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
        if (ibdev->iboe.nb_inet6.notifier_call) {
                if (unregister_inet6addr_notifier(&ibdev->iboe.nb_inet6))
                        pr_warn("failure unregistering notifier\n");
                ibdev->iboe.nb_inet6.notifier_call = NULL;
        }
 #endif
+
        iounmap(ibdev->uar_map);
        for (p = 0; p < ibdev->num_ports; ++p)
                if (ibdev->counters[p] != -1)