Merge tag 'kvm-3.6-1' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[firefly-linux-kernel-4.4.55.git] / drivers / infiniband / hw / mlx4 / main.c
index 3530c41fcd1f28036f0c0a7d951e811bf77752d9..a07b774e78640e90fa7a736f93731dba2a2317e5 100644 (file)
@@ -718,26 +718,53 @@ int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
        return ret;
 }
 
+struct mlx4_ib_steering {
+       struct list_head list;
+       u64 reg_id;
+       union ib_gid gid;
+};
+
 static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
        int err;
        struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
        struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+       u64 reg_id;
+       struct mlx4_ib_steering *ib_steering = NULL;
+
+       if (mdev->dev->caps.steering_mode ==
+           MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               ib_steering = kmalloc(sizeof(*ib_steering), GFP_KERNEL);
+               if (!ib_steering)
+                       return -ENOMEM;
+       }
 
-       err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw,
-                                   !!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
-                                   MLX4_PROT_IB_IPV6);
+       err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, mqp->port,
+                                   !!(mqp->flags &
+                                      MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
+                                   MLX4_PROT_IB_IPV6, &reg_id);
        if (err)
-               return err;
+               goto err_malloc;
 
        err = add_gid_entry(ibqp, gid);
        if (err)
                goto err_add;
 
+       if (ib_steering) {
+               memcpy(ib_steering->gid.raw, gid->raw, 16);
+               ib_steering->reg_id = reg_id;
+               mutex_lock(&mqp->mutex);
+               list_add(&ib_steering->list, &mqp->steering_rules);
+               mutex_unlock(&mqp->mutex);
+       }
        return 0;
 
 err_add:
-       mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6);
+       mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
+                             MLX4_PROT_IB_IPV6, reg_id);
+err_malloc:
+       kfree(ib_steering);
+
        return err;
 }
 
@@ -765,9 +792,30 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        u8 mac[6];
        struct net_device *ndev;
        struct mlx4_ib_gid_entry *ge;
+       u64 reg_id = 0;
+
+       if (mdev->dev->caps.steering_mode ==
+           MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               struct mlx4_ib_steering *ib_steering;
+
+               mutex_lock(&mqp->mutex);
+               list_for_each_entry(ib_steering, &mqp->steering_rules, list) {
+                       if (!memcmp(ib_steering->gid.raw, gid->raw, 16)) {
+                               list_del(&ib_steering->list);
+                               break;
+                       }
+               }
+               mutex_unlock(&mqp->mutex);
+               if (&ib_steering->list == &mqp->steering_rules) {
+                       pr_err("Couldn't find reg_id for mgid. Steering rule is left attached\n");
+                       return -EINVAL;
+               }
+               reg_id = ib_steering->reg_id;
+               kfree(ib_steering);
+       }
 
-       err = mlx4_multicast_detach(mdev->dev,
-                                   &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6);
+       err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
+                                   MLX4_PROT_IB_IPV6, reg_id);
        if (err)
                return err;
 
@@ -1111,7 +1159,8 @@ static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
                        sprintf(name, "mlx4-ib-%d-%d@%s",
                                i, j, dev->pdev->bus->name);
                        /* Set IRQ for specific name (per ring) */
-                       if (mlx4_assign_eq(dev, name, &ibdev->eq_table[eq])) {
+                       if (mlx4_assign_eq(dev, name, NULL,
+                                          &ibdev->eq_table[eq])) {
                                /* Use legacy (same as mlx4_en driver) */
                                pr_warn("Can't allocate EQ %d; reverting to legacy\n", eq);
                                ibdev->eq_table[eq] =