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