net/mlx4_core: Add resource tracking for device managed flow steering rules
authorHadar Hen Zion <hadarh@mellanox.co.il>
Thu, 5 Jul 2012 04:03:47 +0000 (04:03 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 7 Jul 2012 23:23:06 +0000 (16:23 -0700)
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: Hadar Hen Zion <hadarh@mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c

index 0084967be19e0a5bd3e84f142437bc31c176433d..d2c436b10fbf4aff876d8d8fba83fcab64dc9235 100644 (file)
@@ -149,6 +149,7 @@ enum mlx4_resource {
        RES_VLAN,
        RES_EQ,
        RES_COUNTER,
+       RES_FS_RULE,
        MLX4_NUM_OF_RESOURCE_TYPE
 };
 
index 5a6f3555d806c538ffe2d51880ff2956c427140f..c3fa91986190f5b1a27f7d5796906ac923ed6d04 100644 (file)
@@ -190,6 +190,15 @@ struct res_xrcdn {
        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)
 {
        struct rb_node *node = root->rb_node;
@@ -245,6 +254,7 @@ static const char *ResourceType(enum mlx4_resource rt)
        case RES_MAC: return  "RES_MAC";
        case RES_EQ: return "RES_EQ";
        case RES_COUNTER: return "RES_COUNTER";
+       case RES_FS_RULE: return "RES_FS_RULE";
        case RES_XRCD: return "RES_XRCD";
        default: return "Unknown resource type !!!";
        };
@@ -516,6 +526,20 @@ static struct res_common *alloc_xrcdn_tr(int id)
        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,
                                   int extra)
 {
@@ -549,6 +573,9 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
        case RES_XRCD:
                ret = alloc_xrcdn_tr(id);
                break;
+       case RES_FS_RULE:
+               ret = alloc_fs_rule_tr(id);
+               break;
        default:
                return NULL;
        }
@@ -681,6 +708,16 @@ static int remove_xrcdn_ok(struct res_xrcdn *res)
        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)
 {
        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)
                return remove_counter_ok((struct res_counter *)res);
        case RES_XRCD:
                return remove_xrcdn_ok((struct res_xrcdn *)res);
+       case RES_FS_RULE:
+               return remove_fs_rule_ok((struct res_fs_rule *)res);
        default:
                return -EINVAL;
        }
@@ -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_info *cmd)
 {
+       int err;
+
        if (dev->caps.steering_mode !=
            MLX4_STEERING_MODE_DEVICE_MANAGED)
                return -EOPNOTSUPP;
-       return mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
-                           vhcr->in_modifier, 0,
-                           MLX4_QP_FLOW_STEERING_ATTACH,
-                           MLX4_CMD_TIME_CLASS_A,
-                           MLX4_CMD_NATIVE);
+
+       err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
+                          vhcr->in_modifier, 0,
+                          MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
+                          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,
@@ -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_info *cmd)
 {
+       int err;
+
        if (dev->caps.steering_mode !=
            MLX4_STEERING_MODE_DEVICE_MANAGED)
                return -EOPNOTSUPP;
-       return mlx4_cmd(dev, vhcr->in_param, 0, 0,
-                       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
-                       MLX4_CMD_NATIVE);
+
+       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_CMD_NATIVE);
+       return err;
 }
 
 enum {
@@ -3177,6 +3240,58 @@ static void rem_slave_mtts(struct mlx4_dev *dev, int slave)
        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)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -3318,5 +3433,6 @@ 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);
 }