Commit 1b9c6b06 authored by Hadar Hen Zion's avatar Hadar Hen Zion Committed by David S. Miller

net/mlx4_core: Add resource tracking for device managed flow steering rules

As with other device resources, the resource tracker is needed for supporting
device managed flow steering rules under SRIOV: make sure virtual functions
delete only rules created by them, and clean all rules attached by a crashed VF.
Signed-off-by: default avatarHadar Hen Zion <hadarh@mellanox.co.il>
Signed-off-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0ff1fb65
...@@ -149,6 +149,7 @@ enum mlx4_resource { ...@@ -149,6 +149,7 @@ enum mlx4_resource {
RES_VLAN, RES_VLAN,
RES_EQ, RES_EQ,
RES_COUNTER, RES_COUNTER,
RES_FS_RULE,
MLX4_NUM_OF_RESOURCE_TYPE MLX4_NUM_OF_RESOURCE_TYPE
}; };
......
...@@ -190,6 +190,15 @@ struct res_xrcdn { ...@@ -190,6 +190,15 @@ struct res_xrcdn {
int port; int port;
}; };
enum res_fs_rule_states {
RES_FS_RULE_BUSY = RES_ANY_BUSY,
RES_FS_RULE_ALLOCATED,
};
struct res_fs_rule {
struct res_common com;
};
static void *res_tracker_lookup(struct rb_root *root, u64 res_id) static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
{ {
struct rb_node *node = root->rb_node; struct rb_node *node = root->rb_node;
...@@ -245,6 +254,7 @@ static const char *ResourceType(enum mlx4_resource rt) ...@@ -245,6 +254,7 @@ static const char *ResourceType(enum mlx4_resource rt)
case RES_MAC: return "RES_MAC"; case RES_MAC: return "RES_MAC";
case RES_EQ: return "RES_EQ"; case RES_EQ: return "RES_EQ";
case RES_COUNTER: return "RES_COUNTER"; case RES_COUNTER: return "RES_COUNTER";
case RES_FS_RULE: return "RES_FS_RULE";
case RES_XRCD: return "RES_XRCD"; case RES_XRCD: return "RES_XRCD";
default: return "Unknown resource type !!!"; default: return "Unknown resource type !!!";
}; };
...@@ -516,6 +526,20 @@ static struct res_common *alloc_xrcdn_tr(int id) ...@@ -516,6 +526,20 @@ static struct res_common *alloc_xrcdn_tr(int id)
return &ret->com; return &ret->com;
} }
static struct res_common *alloc_fs_rule_tr(u64 id)
{
struct res_fs_rule *ret;
ret = kzalloc(sizeof *ret, GFP_KERNEL);
if (!ret)
return NULL;
ret->com.res_id = id;
ret->com.state = RES_FS_RULE_ALLOCATED;
return &ret->com;
}
static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
int extra) int extra)
{ {
...@@ -549,6 +573,9 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, ...@@ -549,6 +573,9 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
case RES_XRCD: case RES_XRCD:
ret = alloc_xrcdn_tr(id); ret = alloc_xrcdn_tr(id);
break; break;
case RES_FS_RULE:
ret = alloc_fs_rule_tr(id);
break;
default: default:
return NULL; return NULL;
} }
...@@ -681,6 +708,16 @@ static int remove_xrcdn_ok(struct res_xrcdn *res) ...@@ -681,6 +708,16 @@ static int remove_xrcdn_ok(struct res_xrcdn *res)
return 0; return 0;
} }
static int remove_fs_rule_ok(struct res_fs_rule *res)
{
if (res->com.state == RES_FS_RULE_BUSY)
return -EBUSY;
else if (res->com.state != RES_FS_RULE_ALLOCATED)
return -EPERM;
return 0;
}
static int remove_cq_ok(struct res_cq *res) static int remove_cq_ok(struct res_cq *res)
{ {
if (res->com.state == RES_CQ_BUSY) if (res->com.state == RES_CQ_BUSY)
...@@ -722,6 +759,8 @@ static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra) ...@@ -722,6 +759,8 @@ static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra)
return remove_counter_ok((struct res_counter *)res); return remove_counter_ok((struct res_counter *)res);
case RES_XRCD: case RES_XRCD:
return remove_xrcdn_ok((struct res_xrcdn *)res); return remove_xrcdn_ok((struct res_xrcdn *)res);
case RES_FS_RULE:
return remove_fs_rule_ok((struct res_fs_rule *)res);
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -2744,14 +2783,28 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, ...@@ -2744,14 +2783,28 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_mailbox *outbox, struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd) struct mlx4_cmd_info *cmd)
{ {
int err;
if (dev->caps.steering_mode != if (dev->caps.steering_mode !=
MLX4_STEERING_MODE_DEVICE_MANAGED) MLX4_STEERING_MODE_DEVICE_MANAGED)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
vhcr->in_modifier, 0, vhcr->in_modifier, 0,
MLX4_QP_FLOW_STEERING_ATTACH, MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_NATIVE); MLX4_CMD_NATIVE);
if (err)
return err;
err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, 0);
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_ATTACH, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_NATIVE);
}
return err;
} }
int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
...@@ -2760,12 +2813,22 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, ...@@ -2760,12 +2813,22 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_mailbox *outbox, struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd) struct mlx4_cmd_info *cmd)
{ {
int err;
if (dev->caps.steering_mode != if (dev->caps.steering_mode !=
MLX4_STEERING_MODE_DEVICE_MANAGED) MLX4_STEERING_MODE_DEVICE_MANAGED)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return mlx4_cmd(dev, vhcr->in_param, 0, 0,
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;
}
err = mlx4_cmd(dev, vhcr->in_param, 0, 0,
MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_NATIVE); MLX4_CMD_NATIVE);
return err;
} }
enum { enum {
...@@ -3177,6 +3240,58 @@ static void rem_slave_mtts(struct mlx4_dev *dev, int slave) ...@@ -3177,6 +3240,58 @@ static void rem_slave_mtts(struct mlx4_dev *dev, int slave)
spin_unlock_irq(mlx4_tlock(dev)); spin_unlock_irq(mlx4_tlock(dev));
} }
static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_resource_tracker *tracker =
&priv->mfunc.master.res_tracker;
struct list_head *fs_rule_list =
&tracker->slave_list[slave].res_list[RES_FS_RULE];
struct res_fs_rule *fs_rule;
struct res_fs_rule *tmp;
int state;
u64 base;
int err;
err = move_all_busy(dev, slave, RES_FS_RULE);
if (err)
mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n",
slave);
spin_lock_irq(mlx4_tlock(dev));
list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) {
spin_unlock_irq(mlx4_tlock(dev));
if (fs_rule->com.owner == slave) {
base = fs_rule->com.res_id;
state = fs_rule->com.from_state;
while (state != 0) {
switch (state) {
case RES_FS_RULE_ALLOCATED:
/* detach rule */
err = mlx4_cmd(dev, base, 0, 0,
MLX4_QP_FLOW_STEERING_DETACH,
MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_NATIVE);
spin_lock_irq(mlx4_tlock(dev));
rb_erase(&fs_rule->com.node,
&tracker->res_tree[RES_FS_RULE]);
list_del(&fs_rule->com.list);
spin_unlock_irq(mlx4_tlock(dev));
kfree(fs_rule);
state = 0;
break;
default:
state = 0;
}
}
}
spin_lock_irq(mlx4_tlock(dev));
}
spin_unlock_irq(mlx4_tlock(dev));
}
static void rem_slave_eqs(struct mlx4_dev *dev, int slave) static void rem_slave_eqs(struct mlx4_dev *dev, int slave)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
...@@ -3318,5 +3433,6 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) ...@@ -3318,5 +3433,6 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
rem_slave_mtts(dev, slave); rem_slave_mtts(dev, slave);
rem_slave_counters(dev, slave); rem_slave_counters(dev, slave);
rem_slave_xrcdns(dev, slave); rem_slave_xrcdns(dev, slave);
rem_slave_fs_rule(dev, slave);
mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment