mlx4: Add infrastructure for selecting VFs to enable QP0 via MLX proxy QPs
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / resource_tracker.c
index 3b5f53e..ad98162 100644 (file)
@@ -2827,10 +2827,12 @@ static int get_containing_mtt(struct mlx4_dev *dev, int slave, int start,
 }
 
 static int verify_qp_parameters(struct mlx4_dev *dev,
+                               struct mlx4_vhcr *vhcr,
                                struct mlx4_cmd_mailbox *inbox,
                                enum qp_transition transition, u8 slave)
 {
        u32                     qp_type;
+       u32                     qpn;
        struct mlx4_qp_context  *qp_ctx;
        enum mlx4_qp_optpar     optpar;
        int port;
@@ -2870,6 +2872,20 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
                                                return -EINVAL;
                                }
                        break;
+               case MLX4_QP_ST_MLX:
+                       qpn = vhcr->in_modifier & 0x7fffff;
+                       port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+                       if (transition == QP_TRANS_INIT2RTR &&
+                           slave != mlx4_master_func_num(dev) &&
+                           mlx4_is_qp_reserved(dev, qpn) &&
+                           !mlx4_vf_smi_enabled(dev, slave, port)) {
+                               /* only enabled VFs may create MLX proxy QPs */
+                               mlx4_err(dev, "%s: unprivileged slave %d attempting to create an MLX proxy special QP on port %d\n",
+                                        __func__, slave, port);
+                               return -EPERM;
+                       }
+                       break;
+
                default:
                        break;
                }
@@ -3454,7 +3470,7 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
        err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
        if (err)
                return err;
-       err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave);
+       err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_INIT2RTR, slave);
        if (err)
                return err;
 
@@ -3508,7 +3524,7 @@ int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
        err = adjust_qp_sched_queue(dev, slave, context, inbox);
        if (err)
                return err;
-       err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave);
+       err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTR2RTS, slave);
        if (err)
                return err;
 
@@ -3530,7 +3546,7 @@ int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
        err = adjust_qp_sched_queue(dev, slave, context, inbox);
        if (err)
                return err;
-       err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave);
+       err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTS2RTS, slave);
        if (err)
                return err;
 
@@ -3567,7 +3583,7 @@ int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave,
        err = adjust_qp_sched_queue(dev, slave, context, inbox);
        if (err)
                return err;
-       err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave);
+       err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2SQD, slave);
        if (err)
                return err;
 
@@ -3589,7 +3605,7 @@ int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
        err = adjust_qp_sched_queue(dev, slave, context, inbox);
        if (err)
                return err;
-       err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave);
+       err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2RTS, slave);
        if (err)
                return err;
 
@@ -3733,6 +3749,25 @@ static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
        }
 }
 
+static int mlx4_adjust_port(struct mlx4_dev *dev, int slave,
+                           u8 *gid, enum mlx4_protocol prot)
+{
+       int real_port;
+
+       if (prot != MLX4_PROT_ETH)
+               return 0;
+
+       if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0 ||
+           dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               real_port = mlx4_slave_convert_port(dev, slave, gid[5]);
+               if (real_port < 0)
+                       return -EINVAL;
+               gid[5] = real_port;
+       }
+
+       return 0;
+}
+
 int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                               struct mlx4_vhcr *vhcr,
                               struct mlx4_cmd_mailbox *inbox,
@@ -3768,6 +3803,10 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                if (err)
                        goto ex_detach;
        } else {
+               err = mlx4_adjust_port(dev, slave, gid, prot);
+               if (err)
+                       goto ex_put;
+
                err = rem_mcg_res(dev, slave, rqp, gid, prot, type, &reg_id);
                if (err)
                        goto ex_put;