net/mlx4: Add set VF default vlan ID and priority support
[deliverable/linux.git] / drivers / net / ethernet / mellanox / mlx4 / resource_tracker.c
index 083fb48dc3d7bd7bfa014f8ddc9a7eed81dffca5..5083d4babfe32a1822ac2bbb81e8e2fbfd386ac3 100644 (file)
@@ -75,6 +75,7 @@ struct res_gid {
        u8                      gid[16];
        enum mlx4_protocol      prot;
        enum mlx4_steer_type    steer;
+       u64                     reg_id;
 };
 
 enum res_qp_states {
@@ -99,6 +100,7 @@ struct res_qp {
        struct list_head        mcg_list;
        spinlock_t              mcg_spl;
        int                     local_qpn;
+       atomic_t                ref_count;
 };
 
 enum res_mtt_states {
@@ -197,6 +199,7 @@ enum res_fs_rule_states {
 
 struct res_fs_rule {
        struct res_common       com;
+       int                     qpn;
 };
 
 static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
@@ -350,12 +353,45 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
        }
 }
 
+static int update_vport_qp_param(struct mlx4_dev *dev,
+                                struct mlx4_cmd_mailbox *inbox,
+                                u8 slave)
+{
+       struct mlx4_qp_context  *qpc = inbox->buf + 8;
+       struct mlx4_vport_oper_state *vp_oper;
+       struct mlx4_priv *priv;
+       u32 qp_type;
+       int port;
+
+       port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
+       priv = mlx4_priv(dev);
+       vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+
+       if (MLX4_VGT != vp_oper->state.default_vlan) {
+               qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
+               if (MLX4_QP_ST_RC == qp_type)
+                       return -EINVAL;
+
+               qpc->pri_path.vlan_index = vp_oper->vlan_idx;
+               qpc->pri_path.fl = (1 << 6) | (1 << 2); /* set cv bit and hide_cqe_vlan bit*/
+               qpc->pri_path.feup |= 1 << 3; /* set fvl bit */
+               qpc->pri_path.sched_queue &= 0xC7;
+               qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;
+               mlx4_dbg(dev, "qp %d  port %d Q 0x%x set vlan to %d vidx %d feup %x fl %x\n",
+                        be32_to_cpu(qpc->local_qpn) & 0xffffff, port,
+                        (int)(qpc->pri_path.sched_queue), vp_oper->state.default_vlan,
+                        vp_oper->vlan_idx, (int)(qpc->pri_path.feup),
+                        (int)(qpc->pri_path.fl));
+       }
+       return 0;
+}
+
 static int mpt_mask(struct mlx4_dev *dev)
 {
        return dev->caps.num_mpts - 1;
 }
 
-static void *find_res(struct mlx4_dev *dev, int res_id,
+static void *find_res(struct mlx4_dev *dev, u64 res_id,
                      enum mlx4_resource type)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -447,6 +483,7 @@ static struct res_common *alloc_qp_tr(int id)
        ret->local_qpn = id;
        INIT_LIST_HEAD(&ret->mcg_list);
        spin_lock_init(&ret->mcg_spl);
+       atomic_set(&ret->ref_count, 0);
 
        return &ret->com;
 }
@@ -554,7 +591,7 @@ static struct res_common *alloc_xrcdn_tr(int id)
        return &ret->com;
 }
 
-static struct res_common *alloc_fs_rule_tr(u64 id)
+static struct res_common *alloc_fs_rule_tr(u64 id, int qpn)
 {
        struct res_fs_rule *ret;
 
@@ -564,7 +601,7 @@ static struct res_common *alloc_fs_rule_tr(u64 id)
 
        ret->com.res_id = id;
        ret->com.state = RES_FS_RULE_ALLOCATED;
-
+       ret->qpn = qpn;
        return &ret->com;
 }
 
@@ -602,7 +639,7 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
                ret = alloc_xrcdn_tr(id);
                break;
        case RES_FS_RULE:
-               ret = alloc_fs_rule_tr(id);
+               ret = alloc_fs_rule_tr(id, extra);
                break;
        default:
                return NULL;
@@ -671,10 +708,14 @@ undo:
 
 static int remove_qp_ok(struct res_qp *res)
 {
-       if (res->com.state == RES_QP_BUSY)
+       if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) ||
+           !list_empty(&res->mcg_list)) {
+               pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n",
+                      res->com.state, atomic_read(&res->ref_count));
                return -EBUSY;
-       else if (res->com.state != RES_QP_RESERVED)
+       } else if (res->com.state != RES_QP_RESERVED) {
                return -EPERM;
+       }
 
        return 0;
 }
@@ -2790,6 +2831,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
        update_pkey_index(dev, slave, inbox);
        update_gid(dev, inbox, (u8)slave);
        adjust_proxy_tun_qkey(dev, vhcr, qpc);
+       err = update_vport_qp_param(dev, inbox, slave);
+       if (err)
+               return err;
 
        return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
 }
@@ -2927,7 +2971,7 @@ static struct res_gid *find_gid(struct mlx4_dev *dev, int slave,
 
 static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
                       u8 *gid, enum mlx4_protocol prot,
-                      enum mlx4_steer_type steer)
+                      enum mlx4_steer_type steer, u64 reg_id)
 {
        struct res_gid *res;
        int err;
@@ -2944,6 +2988,7 @@ static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
                memcpy(res->gid, gid, 16);
                res->prot = prot;
                res->steer = steer;
+               res->reg_id = reg_id;
                list_add_tail(&res->list, &rqp->mcg_list);
                err = 0;
        }
@@ -2954,7 +2999,7 @@ static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
 
 static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
                       u8 *gid, enum mlx4_protocol prot,
-                      enum mlx4_steer_type steer)
+                      enum mlx4_steer_type steer, u64 *reg_id)
 {
        struct res_gid *res;
        int err;
@@ -2964,6 +3009,7 @@ static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
        if (!res || res->prot != prot || res->steer != steer)
                err = -EINVAL;
        else {
+               *reg_id = res->reg_id;
                list_del(&res->list);
                kfree(res);
                err = 0;
@@ -2973,6 +3019,37 @@ static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
        return err;
 }
 
+static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+                    int block_loopback, enum mlx4_protocol prot,
+                    enum mlx4_steer_type type, u64 *reg_id)
+{
+       switch (dev->caps.steering_mode) {
+       case MLX4_STEERING_MODE_DEVICE_MANAGED:
+               return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5],
+                                               block_loopback, prot,
+                                               reg_id);
+       case MLX4_STEERING_MODE_B0:
+               return mlx4_qp_attach_common(dev, qp, gid,
+                                           block_loopback, prot, type);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+                    enum mlx4_protocol prot, enum mlx4_steer_type type,
+                    u64 reg_id)
+{
+       switch (dev->caps.steering_mode) {
+       case MLX4_STEERING_MODE_DEVICE_MANAGED:
+               return mlx4_flow_detach(dev, reg_id);
+       case MLX4_STEERING_MODE_B0:
+               return mlx4_qp_detach_common(dev, qp, gid, prot, type);
+       default:
+               return -EINVAL;
+       }
+}
+
 int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                               struct mlx4_vhcr *vhcr,
                               struct mlx4_cmd_mailbox *inbox,
@@ -2985,6 +3062,7 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
        int err;
        int qpn;
        struct res_qp *rqp;
+       u64 reg_id = 0;
        int attach = vhcr->op_modifier;
        int block_loopback = vhcr->in_modifier >> 31;
        u8 steer_type_mask = 2;
@@ -2997,30 +3075,32 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
 
        qp.qpn = qpn;
        if (attach) {
-               err = add_mcg_res(dev, slave, rqp, gid, prot, type);
-               if (err)
+               err = qp_attach(dev, &qp, gid, block_loopback, prot,
+                               type, &reg_id);
+               if (err) {
+                       pr_err("Fail to attach rule to qp 0x%x\n", qpn);
                        goto ex_put;
-
-               err = mlx4_qp_attach_common(dev, &qp, gid,
-                                           block_loopback, prot, type);
+               }
+               err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id);
                if (err)
-                       goto ex_rem;
+                       goto ex_detach;
        } else {
-               err = rem_mcg_res(dev, slave, rqp, gid, prot, type);
+               err = rem_mcg_res(dev, slave, rqp, gid, prot, type, &reg_id);
                if (err)
                        goto ex_put;
-               err = mlx4_qp_detach_common(dev, &qp, gid, prot, type);
-       }
 
+               err = qp_detach(dev, &qp, gid, prot, type, reg_id);
+               if (err)
+                       pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n",
+                              qpn, reg_id);
+       }
        put_res(dev, slave, qpn, RES_QP);
-       return 0;
+       return err;
 
-ex_rem:
-       /* ignore error return below, already in error */
-       (void) rem_mcg_res(dev, slave, rqp, gid, prot, type);
+ex_detach:
+       qp_detach(dev, &qp, gid, prot, type, reg_id);
 ex_put:
        put_res(dev, slave, qpn, RES_QP);
-
        return err;
 }
 
@@ -3121,6 +3201,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
        struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC];
        int err;
        int qpn;
+       struct res_qp *rqp;
        struct mlx4_net_trans_rule_hw_ctrl *ctrl;
        struct _rule_hw  *rule_header;
        int header_id;
@@ -3131,7 +3212,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
 
        ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
        qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
-       err = get_res(dev, slave, qpn, RES_QP, NULL);
+       err = get_res(dev, slave, qpn, RES_QP, &rqp);
        if (err) {
                pr_err("Steering rule with qpn 0x%x rejected.\n", qpn);
                return err;
@@ -3172,14 +3253,16 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
        if (err)
                goto err_put;
 
-       err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, 0);
+       err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn);
        if (err) {
                mlx4_err(dev, "Fail to add flow steering resources.\n ");
                /* detach rule*/
                mlx4_cmd(dev, vhcr->out_param, 0, 0,
                         MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
                         MLX4_CMD_NATIVE);
+               goto err_put;
        }
+       atomic_inc(&rqp->ref_count);
 err_put:
        put_res(dev, slave, qpn, RES_QP);
        return err;
@@ -3192,20 +3275,35 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
                                         struct mlx4_cmd_info *cmd)
 {
        int err;
+       struct res_qp *rqp;
+       struct res_fs_rule *rrule;
 
        if (dev->caps.steering_mode !=
            MLX4_STEERING_MODE_DEVICE_MANAGED)
                return -EOPNOTSUPP;
 
+       err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule);
+       if (err)
+               return err;
+       /* Release the rule form busy state before removal */
+       put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
+       err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp);
+       if (err)
+               return err;
+
        err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0);
        if (err) {
                mlx4_err(dev, "Fail to remove flow steering resources.\n ");
-               return err;
+               goto out;
        }
 
        err = mlx4_cmd(dev, vhcr->in_param, 0, 0,
                       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
                       MLX4_CMD_NATIVE);
+       if (!err)
+               atomic_dec(&rqp->ref_count);
+out:
+       put_res(dev, slave, rrule->qpn, RES_QP);
        return err;
 }
 
@@ -3238,9 +3336,16 @@ static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp)
        struct mlx4_qp qp; /* dummy for calling attach/detach */
 
        list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) {
-               qp.qpn = rqp->local_qpn;
-               (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, rgid->prot,
-                                            rgid->steer);
+               switch (dev->caps.steering_mode) {
+               case MLX4_STEERING_MODE_DEVICE_MANAGED:
+                       mlx4_flow_detach(dev, rgid->reg_id);
+                       break;
+               case MLX4_STEERING_MODE_B0:
+                       qp.qpn = rqp->local_qpn;
+                       (void) mlx4_qp_detach_common(dev, &qp, rgid->gid,
+                                                    rgid->prot, rgid->steer);
+                       break;
+               }
                list_del(&rgid->list);
                kfree(rgid);
        }
@@ -3803,6 +3908,7 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
        mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
        /*VLAN*/
        rem_slave_macs(dev, slave);
+       rem_slave_fs_rule(dev, slave);
        rem_slave_qps(dev, slave);
        rem_slave_srqs(dev, slave);
        rem_slave_cqs(dev, slave);
@@ -3811,6 +3917,5 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
        rem_slave_mtts(dev, slave);
        rem_slave_counters(dev, slave);
        rem_slave_xrcdns(dev, slave);
-       rem_slave_fs_rule(dev, slave);
        mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
 }
This page took 0.029955 seconds and 5 git commands to generate.