IB/mlx4: Add support for steerable IB UD QPs
authorMatan Barak <matanb@mellanox.com>
Thu, 7 Nov 2013 13:25:17 +0000 (15:25 +0200)
committerRoland Dreier <roland@purestorage.com>
Tue, 14 Jan 2014 22:06:50 +0000 (14:06 -0800)
This patch adds support for steerable (NETIF) QP creation.  When we
create the device, we allocate a range of steerable QPs.

Afterward when a QP is created with the NETIF flag, it's allocated
from this range.  Allocation is managed by bitmap allocator.

Internal steering rules for those QPs is automatically generated on
their creation.

Signed-off-by: Matan Barak <matanb@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx4/qp.c

index 6b7f227..ea5844e 100644 (file)
@@ -1850,8 +1850,35 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        spin_lock_init(&ibdev->sm_lock);
        mutex_init(&ibdev->cap_mask_mutex);
 
+       if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               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;
@@ -1902,6 +1929,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)
@@ -1922,6 +1956,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;
@@ -1935,6 +2032,13 @@ 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);
+       }
+
        iounmap(ibdev->uar_map);
        for (p = 0; p < ibdev->num_ports; ++p)
                if (ibdev->counters[p] != -1)
index e9fb396..837f9aa 100644 (file)
@@ -68,6 +68,8 @@ enum {
 /*module param to indicate if SM assigns the alias_GUID*/
 extern int mlx4_ib_sm_guid_assign;
 
+#define MLX4_IB_UC_STEER_QPN_ALIGN 1
+#define MLX4_IB_UC_MAX_NUM_QPS     256
 struct mlx4_ib_ucontext {
        struct ib_ucontext      ibucontext;
        struct mlx4_uar         uar;
@@ -153,6 +155,7 @@ struct mlx4_ib_wq {
 enum mlx4_ib_qp_flags {
        MLX4_IB_QP_LSO = IB_QP_CREATE_IPOIB_UD_LSO,
        MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK,
+       MLX4_IB_QP_NETIF = IB_QP_CREATE_NETIF_QP,
        MLX4_IB_SRIOV_TUNNEL_QP = 1 << 30,
        MLX4_IB_SRIOV_SQP = 1 << 31,
 };
@@ -270,6 +273,7 @@ struct mlx4_ib_qp {
        struct list_head        gid_list;
        struct list_head        steering_rules;
        struct mlx4_ib_buf      *sqp_proxy_rcv;
+       u64                     reg_id;
 
 };
 
@@ -494,6 +498,9 @@ struct mlx4_ib_dev {
        struct kobject         *dev_ports_parent[MLX4_MFUNC_MAX];
        struct mlx4_ib_iov_port iov_ports[MLX4_MAX_PORTS];
        struct pkey_mgt         pkeys;
+       unsigned long *ib_uc_qpns_bitmap;
+       int steer_qpn_count;
+       int steer_qpn_base;
        int steering_support;
 };
 
@@ -753,5 +760,9 @@ void mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device);
 
 __be64 mlx4_ib_gen_node_guid(void);
 
+int mlx4_ib_steer_qp_alloc(struct mlx4_ib_dev *dev, int count, int *qpn);
+void mlx4_ib_steer_qp_free(struct mlx4_ib_dev *dev, u32 qpn, int count);
+int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
+                        int is_attach);
 
 #endif /* MLX4_IB_H */
index 4f10af2..387fbf2 100644 (file)
@@ -716,6 +716,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO)
                        qp->flags |= MLX4_IB_QP_LSO;
 
+               if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) {
+                       if (dev->steering_support ==
+                           MLX4_STEERING_MODE_DEVICE_MANAGED)
+                               qp->flags |= MLX4_IB_QP_NETIF;
+                       else
+                               goto err;
+               }
+
                err = set_kernel_sq_size(dev, &init_attr->cap, qp_type, qp);
                if (err)
                        goto err;
@@ -765,7 +773,11 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                if (init_attr->qp_type == IB_QPT_RAW_PACKET)
                        err = mlx4_qp_reserve_range(dev->dev, 1, 1 << 8, &qpn);
                else
-                       err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn);
+                       if (qp->flags & MLX4_IB_QP_NETIF)
+                               err = mlx4_ib_steer_qp_alloc(dev, 1, &qpn);
+                       else
+                               err = mlx4_qp_reserve_range(dev->dev, 1, 1,
+                                                           &qpn);
                if (err)
                        goto err_proxy;
        }
@@ -790,8 +802,12 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
        return 0;
 
 err_qpn:
-       if (!sqpn)
-               mlx4_qp_release_range(dev->dev, qpn, 1);
+       if (!sqpn) {
+               if (qp->flags & MLX4_IB_QP_NETIF)
+                       mlx4_ib_steer_qp_free(dev, qpn, 1);
+               else
+                       mlx4_qp_release_range(dev->dev, qpn, 1);
+       }
 err_proxy:
        if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI)
                free_proxy_bufs(pd->device, qp);
@@ -932,8 +948,12 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
 
        mlx4_qp_free(dev->dev, &qp->mqp);
 
-       if (!is_sqp(dev, qp) && !is_tunnel_qp(dev, qp))
-               mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1);
+       if (!is_sqp(dev, qp) && !is_tunnel_qp(dev, qp)) {
+               if (qp->flags & MLX4_IB_QP_NETIF)
+                       mlx4_ib_steer_qp_free(dev, qp->mqp.qpn, 1);
+               else
+                       mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1);
+       }
 
        mlx4_mtt_cleanup(dev->dev, &qp->mtt);
 
@@ -987,9 +1007,16 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
         */
        if (init_attr->create_flags & ~(MLX4_IB_QP_LSO |
                                        MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK |
-                                       MLX4_IB_SRIOV_TUNNEL_QP | MLX4_IB_SRIOV_SQP))
+                                       MLX4_IB_SRIOV_TUNNEL_QP |
+                                       MLX4_IB_SRIOV_SQP |
+                                       MLX4_IB_QP_NETIF))
                return ERR_PTR(-EINVAL);
 
+       if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) {
+               if (init_attr->qp_type != IB_QPT_UD)
+                       return ERR_PTR(-EINVAL);
+       }
+
        if (init_attr->create_flags &&
            (udata ||
             ((init_attr->create_flags & ~MLX4_IB_SRIOV_SQP) &&
@@ -1235,6 +1262,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        struct mlx4_qp_context *context;
        enum mlx4_qp_optpar optpar = 0;
        int sqd_event;
+       int steer_qp = 0;
        int err = -EINVAL;
 
        context = kzalloc(sizeof *context, GFP_KERNEL);
@@ -1319,6 +1347,11 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                        optpar |= MLX4_QP_OPTPAR_COUNTER_INDEX;
                } else
                        context->pri_path.counter_index = 0xff;
+
+               if (qp->flags & MLX4_IB_QP_NETIF) {
+                       mlx4_ib_steer_qp_reg(dev, qp, 1);
+                       steer_qp = 1;
+               }
        }
 
        if (attr_mask & IB_QP_PKEY_INDEX) {
@@ -1547,9 +1580,14 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                qp->sq_next_wqe = 0;
                if (qp->rq.wqe_cnt)
                        *qp->db.db  = 0;
+
+               if (qp->flags & MLX4_IB_QP_NETIF)
+                       mlx4_ib_steer_qp_reg(dev, qp, 0);
        }
 
 out:
+       if (err && steer_qp)
+               mlx4_ib_steer_qp_reg(dev, qp, 0);
        kfree(context);
        return err;
 }
@@ -2762,6 +2800,9 @@ done:
        if (qp->flags & MLX4_IB_QP_LSO)
                qp_init_attr->create_flags |= IB_QP_CREATE_IPOIB_UD_LSO;
 
+       if (qp->flags & MLX4_IB_QP_NETIF)
+               qp_init_attr->create_flags |= IB_QP_CREATE_NETIF_QP;
+
        qp_init_attr->sq_sig_type =
                qp->sq_signal_bits == cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) ?
                IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;