Add support structures and functions that can be used by NFP to impliment
the indirect block register functionality of TC.

Signed-off-by: John Hurley <john.hur...@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicin...@netronome.com>
---
 drivers/net/ethernet/netronome/nfp/flower/main.c   |  13 +++
 drivers/net/ethernet/netronome/nfp/flower/main.h   |   8 ++
 .../net/ethernet/netronome/nfp/flower/offload.c    | 129 +++++++++++++++++++++
 3 files changed, 150 insertions(+)

diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c 
b/drivers/net/ethernet/netronome/nfp/flower/main.c
index 3a54728..518006c 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.c
@@ -568,8 +568,18 @@ static int nfp_flower_init(struct nfp_app *app)
                goto err_cleanup_metadata;
        }
 
+       INIT_LIST_HEAD(&app_priv->indr_block_cb_priv);
+       app_priv->indr_block_owner = tc_indr_block_owner_create();
+       if (!app_priv->indr_block_owner) {
+               err = -ENOMEM;
+               goto err_lag_clean;
+       }
+
        return 0;
 
+err_lag_clean:
+       if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG)
+               nfp_flower_lag_cleanup(&app_priv->nfp_lag);
 err_cleanup_metadata:
        nfp_flower_metadata_cleanup(app);
 err_free_app_priv:
@@ -588,6 +598,8 @@ static void nfp_flower_clean(struct nfp_app *app)
        if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG)
                nfp_flower_lag_cleanup(&app_priv->nfp_lag);
 
+       nfp_flower_clean_indr_block_priv(app);
+
        nfp_flower_metadata_cleanup(app);
        vfree(app->priv);
        app->priv = NULL;
@@ -678,6 +690,7 @@ static void nfp_flower_stop(struct nfp_app *app)
                unregister_netdevice_notifier(&app_priv->nfp_lag.lag_nb);
 
        nfp_tunnel_config_stop(app);
+       tc_indr_block_owner_clean(app_priv->indr_block_owner);
 }
 
 const struct nfp_app_type app_flower = {
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h 
b/drivers/net/ethernet/netronome/nfp/flower/main.h
index a91ac52..8b4bcf3 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -133,6 +133,8 @@ struct nfp_fl_lag {
  * @reify_wait_queue:  wait queue for repr reify response counting
  * @mtu_conf:          Configuration of repr MTU value
  * @nfp_lag:           Link aggregation data block
+ * @indr_block_cb_priv:        List of priv data passed to indirect block 
registers
+ * @indr_block_owner:  Struct required for indirect blocks
  */
 struct nfp_flower_priv {
        struct nfp_app *app;
@@ -166,6 +168,8 @@ struct nfp_flower_priv {
        wait_queue_head_t reify_wait_queue;
        struct nfp_mtu_conf mtu_conf;
        struct nfp_fl_lag nfp_lag;
+       struct list_head indr_block_cb_priv;
+       struct tcf_indr_block_owner *indr_block_owner;
 };
 
 /**
@@ -269,5 +273,9 @@ int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
                                       struct nfp_fl_pre_lag *pre_act);
 int nfp_flower_lag_get_output_id(struct nfp_app *app,
                                 struct net_device *master);
+void
+nfp_flower_register_indr_block(struct nfp_app *app, struct net_device *netdev);
+void nfp_flower_unregister_indr_block(struct net_device *netdev);
+void nfp_flower_clean_indr_block_priv(struct nfp_app *app);
 
 #endif
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c 
b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 2c32edf..f701b2e 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -693,3 +693,132 @@ int nfp_flower_setup_tc(struct nfp_app *app, struct 
net_device *netdev,
                return -EOPNOTSUPP;
        }
 }
+
+struct nfp_flower_indr_block_cb_priv {
+       struct net_device *netdev;
+       struct nfp_app *app;
+       struct list_head list;
+};
+
+static struct nfp_flower_indr_block_cb_priv *
+nfp_flower_indr_block_cb_priv_lookup(struct nfp_app *app,
+                                    struct net_device *netdev)
+{
+       struct nfp_flower_indr_block_cb_priv *cb_priv;
+       struct nfp_flower_priv *priv = app->priv;
+
+       /* All callback list access should be protected by RTNL. */
+       ASSERT_RTNL();
+
+       list_for_each_entry(cb_priv, &priv->indr_block_cb_priv, list)
+               if (cb_priv->netdev == netdev)
+                       return cb_priv;
+
+       return NULL;
+}
+
+void nfp_flower_clean_indr_block_priv(struct nfp_app *app)
+{
+       struct nfp_flower_indr_block_cb_priv *cb_priv, *temp;
+       struct nfp_flower_priv *priv = app->priv;
+
+       list_for_each_entry_safe(cb_priv, temp, &priv->indr_block_cb_priv, list)
+               kfree(cb_priv);
+}
+
+static int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
+                                         void *type_data, void *cb_priv)
+{
+       struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
+       struct tc_cls_flower_offload *flower = type_data;
+
+       if (flower->common.chain_index)
+               return -EOPNOTSUPP;
+
+       switch (type) {
+       case TC_SETUP_CLSFLOWER:
+               return nfp_flower_repr_offload(priv->app, priv->netdev,
+                                              type_data, false);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+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;
+
+       if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+               return -EOPNOTSUPP;
+
+       switch (f->command) {
+       case TC_BLOCK_BIND:
+               cb_priv = kmalloc(sizeof(*cb_priv), GFP_KERNEL);
+               if (!cb_priv)
+                       return -ENOMEM;
+
+               cb_priv->netdev = netdev;
+               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,
+                                           netdev, cb_priv, f->extack);
+               if (err) {
+                       list_del(&cb_priv->list);
+                       kfree(cb_priv);
+               }
+
+               return err;
+       case TC_BLOCK_UNBIND:
+               tcf_block_cb_unregister(f->block,
+                                       nfp_flower_setup_indr_block_cb, netdev);
+               cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
+               if (cb_priv) {
+                       list_del(&cb_priv->list);
+                       kfree(cb_priv);
+               }
+
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static int
+nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
+                           enum tc_setup_type type, void *type_data)
+{
+       switch (type) {
+       case TC_SETUP_BLOCK:
+               return nfp_flower_setup_indr_tc_block(netdev, cb_priv,
+                                                     type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+void
+nfp_flower_register_indr_block(struct nfp_app *app, struct net_device *netdev)
+{
+       struct nfp_flower_priv *priv = app->priv;
+       int err;
+
+       err = __tc_indr_block_cb_register(netdev, app,
+                                         nfp_flower_indr_setup_tc_cb, netdev,
+                                         priv->indr_block_owner);
+       if (err)
+               nfp_flower_cmsg_warn(priv->app,
+                                    "Failed to reg indirect block cb for 
%s\n", netdev->name);
+}
+
+void nfp_flower_unregister_indr_block(struct net_device *netdev)
+{
+       __tc_indr_block_cb_unregister(netdev, nfp_flower_indr_setup_tc_cb,
+                                     netdev);
+}
-- 
2.7.4

Reply via email to