net: sched: add API for registering unlocked offload block callbacks
authorVlad Buslov <vladbu@mellanox.com>
Mon, 26 Aug 2019 13:45:01 +0000 (16:45 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 26 Aug 2019 21:17:43 +0000 (14:17 -0700)
Extend struct flow_block_offload with "unlocked_driver_cb" flag to allow
registering and unregistering block hardware offload callbacks that do not
require caller to hold rtnl lock. Extend tcf_block with additional
lockeddevcnt counter that is incremented for each non-unlocked driver
callback attached to device. This counter is necessary to conditionally
obtain rtnl lock before calling hardware callbacks in following patches.

Register mlx5 tc block offload callbacks as "unlocked".

Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
include/net/flow_offload.h
include/net/sch_generic.h
net/sched/cls_api.c

index fa4bf2d4bcd4f702e66dd96ce1e7eb15b8004ba5..8592b98d0e70cf5acd5c34dc322b7994765f0f54 100644 (file)
@@ -3470,10 +3470,12 @@ static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
                          void *type_data)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
+       struct flow_block_offload *f = type_data;
 
        switch (type) {
 #ifdef CONFIG_MLX5_ESWITCH
        case TC_SETUP_BLOCK:
+               f->unlocked_driver_cb = true;
                return flow_block_cb_setup_simple(type_data,
                                                  &mlx5e_block_cb_list,
                                                  mlx5e_setup_tc_block_cb,
index 3c0d36b2b91c1efd8821edf1407d3b234a7b5571..e7ac6233037d1e0a86b203d49918781aa8ccae45 100644 (file)
@@ -763,6 +763,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
        if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
                return -EOPNOTSUPP;
 
+       f->unlocked_driver_cb = true;
        f->driver_block_list = &mlx5e_block_cb_list;
 
        switch (f->command) {
@@ -1245,9 +1246,11 @@ static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
                              void *type_data)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
+       struct flow_block_offload *f = type_data;
 
        switch (type) {
        case TC_SETUP_BLOCK:
+               f->unlocked_driver_cb = true;
                return flow_block_cb_setup_simple(type_data,
                                                  &mlx5e_rep_block_cb_list,
                                                  mlx5e_rep_setup_tc_cb,
index 757fa84de65456b141478e5c7b9484313a510865..fc881875f85624c71b6d57ec5d3fdc3b33e08022 100644 (file)
@@ -284,6 +284,7 @@ struct flow_block_offload {
        enum flow_block_command command;
        enum flow_block_binder_type binder_type;
        bool block_shared;
+       bool unlocked_driver_cb;
        struct net *net;
        struct flow_block *block;
        struct list_head cb_list;
index c4fbbaff30a2e6717dde9644652a4b792a062e79..43f5b7ed02bdbad6f5dba54ba79b8f1b9d144d16 100644 (file)
@@ -408,6 +408,7 @@ struct tcf_block {
        bool keep_dst;
        atomic_t offloadcnt; /* Number of oddloaded filters */
        unsigned int nooffloaddevcnt; /* Number of devs unable to do offload */
+       unsigned int lockeddevcnt; /* Number of devs that require rtnl lock. */
        struct {
                struct tcf_chain *chain;
                struct list_head filter_chain_list;
index 8b807e75fae21e75f7615fad746dcbe9709590a3..1a39779bdbadee970b0c3951ba6cf57f6650c6b1 100644 (file)
@@ -1418,6 +1418,8 @@ static int tcf_block_bind(struct tcf_block *block,
                                                  bo->extack);
                if (err)
                        goto err_unroll;
+               if (!bo->unlocked_driver_cb)
+                       block->lockeddevcnt++;
 
                i++;
        }
@@ -1433,6 +1435,8 @@ err_unroll:
                                                    block_cb->cb_priv, false,
                                                    tcf_block_offload_in_use(block),
                                                    NULL);
+                       if (!bo->unlocked_driver_cb)
+                               block->lockeddevcnt--;
                }
                flow_block_cb_free(block_cb);
        }
@@ -1454,6 +1458,8 @@ static void tcf_block_unbind(struct tcf_block *block,
                                            NULL);
                list_del(&block_cb->list);
                flow_block_cb_free(block_cb);
+               if (!bo->unlocked_driver_cb)
+                       block->lockeddevcnt--;
        }
 }