diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4/resource_tracker.c')
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 48 | 
1 files changed, 38 insertions, 10 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 083fb48dc3d..1391b52f443 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -99,6 +99,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 +198,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) @@ -355,7 +357,7 @@ 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 +449,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 +557,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 +567,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 +605,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 +674,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;  } @@ -2990,6 +2997,9 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,  	u8 steer_type_mask = 2;  	enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; +	if (dev->caps.steering_mode != MLX4_STEERING_MODE_B0) +		return -EINVAL; +  	qpn = vhcr->in_modifier & 0xffffff;  	err = get_res(dev, slave, qpn, RES_QP, &rqp);  	if (err) @@ -3121,6 +3131,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 +3142,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 +3183,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 +3205,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;  } @@ -3803,6 +3831,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 +3840,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);  }  |