This allows us to register / unregister tcf_block_cb objects from the
core. The idea is to allocate the tcf_block_cb object from the driver,
attach it to the tc_block_offload->cb_list, then the core registers
them.

Signed-off-by: Pablo Neira Ayuso <[email protected]>
---
 drivers/net/ethernet/mellanox/mlx5/core/en_rep.c   | 33 +++++++----
 drivers/net/ethernet/mellanox/mlxsw/spectrum.c     | 64 +++++++++++++---------
 .../net/ethernet/netronome/nfp/flower/offload.c    | 33 +++++++----
 include/net/pkt_cls.h                              |  6 +-
 net/dsa/slave.c                                    | 15 ++++-
 net/sched/cls_api.c                                | 35 ++++++++----
 6 files changed, 124 insertions(+), 62 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index ee63a902c261..f09135b7a605 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -697,13 +697,21 @@ static int mlx5e_rep_indr_setup_block_cb(enum 
tc_setup_type type,
        }
 }
 
+static void mlx5e_rep_indr_tc_block_unbind(void *cb_priv)
+{
+       struct mlx5e_rep_indr_block_priv *indr_priv = cb_priv;
+
+       list_del(&indr_priv->list);
+       kfree(indr_priv);
+}
+
 static int
 mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
                              struct mlx5e_rep_priv *rpriv,
                              struct tc_block_offload *f)
 {
        struct mlx5e_rep_indr_block_priv *indr_priv;
-       int err = 0;
+       struct tcf_block_cb *block_cb;
 
        if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
                return -EOPNOTSUPP;
@@ -723,26 +731,29 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
                list_add(&indr_priv->list,
                         &rpriv->uplink_priv.tc_indr_block_priv_list);
 
-               err = tcf_block_cb_register(f->block,
-                                           mlx5e_rep_indr_setup_block_cb,
-                                           indr_priv, indr_priv, f->extack);
-               if (err) {
+               block_cb = tcf_block_cb_alloc(f->block->index,
+                                             mlx5e_rep_indr_setup_block_cb,
+                                             indr_priv, indr_priv,
+                                             mlx5e_rep_indr_tc_block_unbind);
+               if (!block_cb) {
                        list_del(&indr_priv->list);
                        kfree(indr_priv);
                }
+               tcf_block_cb_list_add(block_cb, &f->cb_list);
 
-               return err;
+               return 0;
        case TC_BLOCK_UNBIND:
                indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
                if (!indr_priv)
                        return -ENOENT;
 
-               tcf_block_cb_unregister(f->block,
-                                       mlx5e_rep_indr_setup_block_cb,
-                                       indr_priv);
-               list_del(&indr_priv->list);
-               kfree(indr_priv);
+               block_cb = tcf_block_cb_lookup(f->block->index,
+                                              mlx5e_rep_indr_setup_block_cb,
+                                              indr_priv);
+               if (!block_cb)
+                       return -ENOENT;
 
+               tcf_block_cb_list_move(block_cb, &f->cb_list);
                return 0;
        default:
                return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c 
b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index fc325f1213fb..c07fa0487b39 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1514,25 +1514,34 @@ static int mlxsw_sp_setup_tc_block_cb_flower(enum 
tc_setup_type type,
        }
 }
 
+static void mlxsw_sp_tc_block_flower_release(void *cb_priv)
+{
+       struct mlxsw_sp_acl_block *acl_block = cb_priv;
+
+       mlxsw_sp_acl_block_destroy(acl_block);
+}
+
 static int
 mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
-                                   struct tcf_block *block, bool ingress,
-                                   struct netlink_ext_ack *extack)
+                                   struct tc_block_offload *f, bool ingress)
 {
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       struct net *net = dev_net(mlxsw_sp_port->dev);
        struct mlxsw_sp_acl_block *acl_block;
        struct tcf_block_cb *block_cb;
        int err;
 
-       block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
+       block_cb = tcf_block_cb_lookup(f->block->index,
+                                      mlxsw_sp_setup_tc_block_cb_flower,
                                       mlxsw_sp);
        if (!block_cb) {
-               acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, block->net);
+               acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, net);
                if (!acl_block)
                        return -ENOMEM;
-               block_cb = __tcf_block_cb_register(block,
-                                                  
mlxsw_sp_setup_tc_block_cb_flower,
-                                                  mlxsw_sp, acl_block, extack);
+               block_cb = tcf_block_cb_alloc(f->block->index,
+                                             mlxsw_sp_setup_tc_block_cb_flower,
+                                             mlxsw_sp, acl_block,
+                                             mlxsw_sp_tc_block_flower_release);
                if (IS_ERR(block_cb)) {
                        err = PTR_ERR(block_cb);
                        goto err_cb_register;
@@ -1551,27 +1560,28 @@ mlxsw_sp_setup_tc_block_flower_bind(struct 
mlxsw_sp_port *mlxsw_sp_port,
        else
                mlxsw_sp_port->eg_acl_block = acl_block;
 
+       tcf_block_cb_list_add(block_cb, &f->cb_list);
        return 0;
 
 err_block_bind:
        if (!tcf_block_cb_decref(block_cb)) {
-               __tcf_block_cb_unregister(block, block_cb);
 err_cb_register:
-               mlxsw_sp_acl_block_destroy(acl_block);
+               tcf_block_cb_free(block_cb);
        }
        return err;
 }
 
 static void
 mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
-                                     struct tcf_block *block, bool ingress)
+                                     struct tc_block_offload *f, bool ingress)
 {
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_acl_block *acl_block;
        struct tcf_block_cb *block_cb;
        int err;
 
-       block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
+       block_cb = tcf_block_cb_lookup(f->block->index,
+                                      mlxsw_sp_setup_tc_block_cb_flower,
                                       mlxsw_sp);
        if (!block_cb)
                return;
@@ -1584,15 +1594,14 @@ mlxsw_sp_setup_tc_block_flower_unbind(struct 
mlxsw_sp_port *mlxsw_sp_port,
        acl_block = tcf_block_cb_priv(block_cb);
        err = mlxsw_sp_acl_block_unbind(mlxsw_sp, acl_block,
                                        mlxsw_sp_port, ingress);
-       if (!err && !tcf_block_cb_decref(block_cb)) {
-               __tcf_block_cb_unregister(block, block_cb);
-               mlxsw_sp_acl_block_destroy(acl_block);
-       }
+       if (!err && !tcf_block_cb_decref(block_cb))
+               tcf_block_cb_list_move(block_cb, &f->cb_list);
 }
 
 static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
                                   struct tc_block_offload *f)
 {
+       struct tcf_block_cb *block_cb;
        tc_setup_cb_t *cb;
        bool ingress;
        int err;
@@ -1609,22 +1618,27 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port 
*mlxsw_sp_port,
 
        switch (f->command) {
        case TC_BLOCK_BIND:
-               err = tcf_block_cb_register(f->block, cb, mlxsw_sp_port,
-                                           mlxsw_sp_port, f->extack);
-               if (err)
-                       return err;
-               err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port,
-                                                         f->block, ingress,
-                                                         f->extack);
+               block_cb = tcf_block_cb_alloc(f->block->index, cb, 
mlxsw_sp_port,
+                                        mlxsw_sp_port, NULL);
+               if (!block_cb)
+                       return -ENOMEM;
+               err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port, f,
+                                                         ingress);
                if (err) {
-                       tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
+                       tcf_block_cb_free(block_cb);
                        return err;
                }
+               tcf_block_cb_list_add(block_cb, &f->cb_list);
                return 0;
        case TC_BLOCK_UNBIND:
                mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
-                                                     f->block, ingress);
-               tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
+                                                     f, ingress);
+               block_cb = tcf_block_cb_lookup(f->block->index, cb,
+                                              mlxsw_sp_port);
+               if (!block_cb)
+                       return -ENOENT;
+
+               tcf_block_cb_list_move(block_cb, &f->cb_list);
                return 0;
        default:
                return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c 
b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index ba41252b1c14..d2bc36859952 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1246,13 +1246,21 @@ static int nfp_flower_setup_indr_block_cb(enum 
tc_setup_type type,
        }
 }
 
+static void nfp_flower_setup_indr_tc_release(void *cb_priv)
+{
+       struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
+
+       list_del(&priv->list);
+       kfree(priv);
+}
+
 static int
 nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
                               struct tc_block_offload *f)
 {
        struct nfp_flower_indr_block_cb_priv *cb_priv;
        struct nfp_flower_priv *priv = app->priv;
-       int err;
+       struct tcf_block_cb *block_cb;
 
        if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
            !(f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
@@ -1269,26 +1277,29 @@ nfp_flower_setup_indr_tc_block(struct net_device 
*netdev, struct nfp_app *app,
                cb_priv->app = app;
                list_add(&cb_priv->list, &priv->indr_block_cb_priv);
 
-               err = tcf_block_cb_register(f->block,
-                                           nfp_flower_setup_indr_block_cb,
-                                           cb_priv, cb_priv, f->extack);
-               if (err) {
+               block_cb = tcf_block_cb_alloc(f->block->index,
+                                             nfp_flower_setup_indr_block_cb,
+                                             cb_priv, cb_priv,
+                                             nfp_flower_setup_indr_tc_release);
+               if (!block_cb) {
                        list_del(&cb_priv->list);
                        kfree(cb_priv);
                }
 
-               return err;
+               tcf_block_cb_list_add(block_cb, &f->cb_list);
+               return 0;
        case TC_BLOCK_UNBIND:
                cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
                if (!cb_priv)
                        return -ENOENT;
 
-               tcf_block_cb_unregister(f->block,
-                                       nfp_flower_setup_indr_block_cb,
-                                       cb_priv);
-               list_del(&cb_priv->list);
-               kfree(cb_priv);
+               block_cb = tcf_block_cb_lookup(f->block->index,
+                                              nfp_flower_setup_indr_block_cb,
+                                              cb_priv);
+               if (!block_cb)
+                       return -ENOENT;
 
+               tcf_block_cb_list_move(block_cb, &f->cb_list);
                return 0;
        default:
                return -EOPNOTSUPP;
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 7a50f7bb6880..8f0486a00d70 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -71,7 +71,7 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block 
*block)
        return block->q;
 }
 
-struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
+struct tcf_block_cb *tcf_block_cb_alloc(u32 block_index, tc_setup_cb_t *cb,
                                        void *cb_ident, void *cb_priv,
                                        void (*release)(void *cb_priv));
 void tcf_block_cb_free(struct tcf_block_cb *block_cb);
@@ -79,8 +79,8 @@ void tcf_block_cb_list_add(struct tcf_block_cb *block_cb, 
struct list_head *cb_l
 void tcf_block_cb_list_move(struct tcf_block_cb *block_cb, struct list_head 
*cb_list);
 
 void *tcf_block_cb_priv(struct tcf_block_cb *block_cb);
-struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
-                                        tc_setup_cb_t *cb, void *cb_ident);
+struct tcf_block_cb *tcf_block_cb_lookup(u32 block_index, tc_setup_cb_t *cb,
+                                        void *cb_ident);
 void tcf_block_cb_incref(struct tcf_block_cb *block_cb);
 unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb);
 struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index ce26dddc8270..7ef34cc2f574 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -902,6 +902,7 @@ static int dsa_slave_setup_tc_block_cb_eg(enum 
tc_setup_type type,
 static int dsa_slave_setup_tc_block(struct net_device *dev,
                                    struct tc_block_offload *f)
 {
+       struct tcf_block_cb *block_cb;
        tc_setup_cb_t *cb;
 
        if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
@@ -913,9 +914,19 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
 
        switch (f->command) {
        case TC_BLOCK_BIND:
-               return tcf_block_cb_register(f->block, cb, dev, dev, f->extack);
+               block_cb = tcf_block_cb_alloc(f->block->index, cb, dev, dev,
+                                             NULL);
+               if (!block_cb)
+                       return -ENOMEM;
+
+               tcf_block_cb_list_add(block_cb, &f->cb_list);
+               return 0;
        case TC_BLOCK_UNBIND:
-               tcf_block_cb_unregister(f->block, cb, dev);
+               block_cb = tcf_block_cb_lookup(f->block->index, cb, dev);
+               if (!block_cb)
+                       return -ENOENT;
+
+               tcf_block_cb_list_move(block_cb, &f->cb_list);
                return 0;
        default:
                return -EOPNOTSUPP;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index a00463c8cfa9..f7f6f42d58d1 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -714,6 +714,7 @@ struct tcf_block_cb {
        void (*release)(void *cb_priv);
        void *cb_ident;
        void *cb_priv;
+       u32 block_index;
        unsigned int refcnt;
 };
 
@@ -730,12 +731,14 @@ EXPORT_SYMBOL(tcf_block_cb_priv);
 
 static LIST_HEAD(tcf_block_cb_list);
 
-struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
-                                        tc_setup_cb_t *cb, void *cb_ident)
+struct tcf_block_cb *tcf_block_cb_lookup(u32 block_index, tc_setup_cb_t *cb,
+                                        void *cb_ident)
 {      struct tcf_block_cb *block_cb;
 
-       list_for_each_entry(block_cb, &block->cb_list, list)
-               if (block_cb->cb == cb && block_cb->cb_ident == cb_ident)
+       list_for_each_entry(block_cb, &tcf_block_cb_list, list)
+               if (block_cb->block_index == block_index &&
+                   block_cb->cb == cb &&
+                   block_cb->cb_ident == cb_ident)
                        return block_cb;
        return NULL;
 }
@@ -753,7 +756,7 @@ unsigned int tcf_block_cb_decref(struct tcf_block_cb 
*block_cb)
 }
 EXPORT_SYMBOL(tcf_block_cb_decref);
 
-struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
+struct tcf_block_cb *tcf_block_cb_alloc(u32 block_index, tc_setup_cb_t *cb,
                                        void *cb_ident, void *cb_priv,
                                        void (*release)(void *cb_priv))
 {
@@ -767,6 +770,7 @@ struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
        block_cb->cb_ident = cb_ident;
        block_cb->release = release;
        block_cb->cb_priv = cb_priv;
+       block_cb->block_index = block_index;
 
        return block_cb;
 }
@@ -810,7 +814,7 @@ struct tcf_block_cb *__tcf_block_cb_register(struct 
tcf_block *block,
        if (err)
                return ERR_PTR(err);
 
-       block_cb = tcf_block_cb_alloc(cb, cb_ident, cb_priv, NULL);
+       block_cb = tcf_block_cb_alloc(block->index, cb, cb_ident, cb_priv, 
NULL);
        if (!block_cb)
                return ERR_PTR(-ENOMEM);
 
@@ -847,7 +851,7 @@ void tcf_block_cb_unregister(struct tcf_block *block,
 {
        struct tcf_block_cb *block_cb;
 
-       block_cb = tcf_block_cb_lookup(block, cb, cb_ident);
+       block_cb = tcf_block_cb_lookup(block->index, cb, cb_ident);
        if (!block_cb)
                return;
        __tcf_block_cb_unregister(block, block_cb);
@@ -929,16 +933,27 @@ static int tcf_block_setup(struct tcf_block *block, 
struct tc_block_offload *bo)
 int tcf_setup_block_offload(struct tc_block_offload *f, tc_setup_cb_t *cb,
                            void *cb_priv, bool ingress_only)
 {
+       struct tcf_block_cb *block_cb;
+
        if (ingress_only &&
            f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
                return -EOPNOTSUPP;
 
        switch (f->command) {
        case TC_BLOCK_BIND:
-               return tcf_block_cb_register(f->block, cb, cb_priv, cb_priv,
-                                            f->extack);
+               block_cb = tcf_block_cb_alloc(f->block->index, cb, cb_priv,
+                                             cb_priv, NULL);
+               if (!block_cb)
+                       return -ENOMEM;
+
+               tcf_block_cb_list_add(block_cb, &f->cb_list);
+               return 0;
        case TC_BLOCK_UNBIND:
-               tcf_block_cb_unregister(f->block, cb, cb_priv);
+               block_cb = tcf_block_cb_lookup(f->block->index, cb, cb_priv);
+               if (!block_cb)
+                       return -ENOENT;
+
+               tcf_block_cb_list_move(block_cb, &f->cb_list);
                return 0;
        default:
                return -EOPNOTSUPP;
-- 
2.11.0

Reply via email to