mlx4_core: Disable memory windows for virtual functions
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / resource_tracker.c
index 2287dfd..9185e2e 100644 (file)
@@ -1796,6 +1796,26 @@ static int mr_get_mtt_size(struct mlx4_mpt_entry *mpt)
        return be32_to_cpu(mpt->mtt_sz);
 }
 
+static u32 mr_get_pd(struct mlx4_mpt_entry *mpt)
+{
+       return be32_to_cpu(mpt->pd_flags) & 0x00ffffff;
+}
+
+static int mr_is_fmr(struct mlx4_mpt_entry *mpt)
+{
+       return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG;
+}
+
+static int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt)
+{
+       return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE;
+}
+
+static int mr_is_region(struct mlx4_mpt_entry *mpt)
+{
+       return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION;
+}
+
 static int qp_get_mtt_addr(struct mlx4_qp_context *qpc)
 {
        return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8;
@@ -1856,12 +1876,41 @@ int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave,
        int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz;
        int phys;
        int id;
+       u32 pd;
+       int pd_slave;
 
        id = index & mpt_mask(dev);
        err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt);
        if (err)
                return err;
 
+       /* Disable memory windows for VFs. */
+       if (!mr_is_region(inbox->buf)) {
+               err = -EPERM;
+               goto ex_abort;
+       }
+
+       /* Make sure that the PD bits related to the slave id are zeros. */
+       pd = mr_get_pd(inbox->buf);
+       pd_slave = (pd >> 17) & 0x7f;
+       if (pd_slave != 0 && pd_slave != slave) {
+               err = -EPERM;
+               goto ex_abort;
+       }
+
+       if (mr_is_fmr(inbox->buf)) {
+               /* FMR and Bind Enable are forbidden in slave devices. */
+               if (mr_is_bind_enabled(inbox->buf)) {
+                       err = -EPERM;
+                       goto ex_abort;
+               }
+               /* FMR and Memory Windows are also forbidden. */
+               if (!mr_is_region(inbox->buf)) {
+                       err = -EPERM;
+                       goto ex_abort;
+               }
+       }
+
        phys = mr_phys_mpt(inbox->buf);
        if (!phys) {
                err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);