From: Jakub Kicinski Date: Thu, 8 Feb 2018 04:55:24 +0000 (-0800) Subject: nfp: forbid disabling hw-tc-offload on representors while offload active X-Git-Tag: Ubuntu-4.15.0-14.15~217 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=91e2310bb5573d4541a6aaa2df9cf10ed2b35536;p=mirror_ubuntu-bionic-kernel.git nfp: forbid disabling hw-tc-offload on representors while offload active BugLink: http://bugs.launchpad.net/bugs/1752828 All netdevs which can accept TC offloads must implement .ndo_set_features(). nfp_reprs currently do not do that, which means hw-tc-offload can be turned on and off even when offloads are active. Whether the offloads are active is really a question to nfp_ports, so remove the per-app tc_busy callback indirection thing, and simply count the number of offloaded items in nfp_port structure. Fixes: 8a2768732a4d ("nfp: provide infrastructure for offloading flower based TC filters") Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Tested-by: Pieter Jansen van Vuuren Signed-off-by: David S. Miller (back-ported from commit d692403e5cf8008f31f5664a6f3ce3e65d54f458) Signed-off-by: Kamal Mostafa Signed-off-by: Seth Forshee --- diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index 9af15d1b0b7f..42223170b1e6 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -164,6 +164,7 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type, return err; bv->tc_prog = cls_bpf->prog; + nn->port->tc_offload_cnt = !!bv->tc_prog; return 0; } @@ -201,11 +202,6 @@ static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev, } } -static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn) -{ - return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF; -} - const struct nfp_app_type app_bpf = { .id = NFP_APP_BPF_NIC, .name = "ebpf", @@ -216,7 +212,6 @@ const struct nfp_app_type app_bpf = { .vnic_free = nfp_bpf_vnic_free, .setup_tc = nfp_bpf_setup_tc, - .tc_busy = nfp_bpf_tc_busy, .xdp_offload = nfp_bpf_xdp_offload, .bpf_verifier_prep = nfp_bpf_verifier_prep, diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 553f94f55dce..5521da60735a 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -325,6 +325,7 @@ static int nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, struct tc_cls_flower_offload *flow, bool egress) { + struct nfp_port *port = nfp_port_from_netdev(netdev); struct nfp_flower_priv *priv = app->priv; struct nfp_fl_payload *flow_pay; struct nfp_fl_key_ls *key_layer; @@ -364,6 +365,7 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, INIT_HLIST_NODE(&flow_pay->link); flow_pay->tc_flower_cookie = flow->cookie; hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie); + port->tc_offload_cnt++; /* Deallocate flow payload when flower rule has been destroyed. */ kfree(key_layer); @@ -395,6 +397,7 @@ static int nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, struct tc_cls_flower_offload *flow) { + struct nfp_port *port = nfp_port_from_netdev(netdev); struct nfp_fl_payload *nfp_flow; int err; @@ -416,6 +419,7 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, err_free_flow: hash_del_rcu(&nfp_flow->link); + port->tc_offload_cnt--; kfree(nfp_flow->action_data); kfree(nfp_flow->mask_data); kfree(nfp_flow->unmasked_data); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 0e5e0305ad1c..6d0d599aaa8e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -84,7 +84,6 @@ extern const struct nfp_app_type app_flower; * @stop: stop application logic * @ctrl_msg_rx: control message handler * @setup_tc: setup TC ndo - * @tc_busy: TC HW offload busy (rules loaded) * @xdp_offload: offload an XDP program * @bpf_verifier_prep: verifier prep for dev-specific BPF programs * @bpf_translate: translate call for dev-specific BPF programs @@ -124,7 +123,6 @@ struct nfp_app_type { int (*setup_tc)(struct nfp_app *app, struct net_device *netdev, enum tc_setup_type type, void *type_data); - bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn); int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn, struct bpf_prog *prog); int (*bpf_verifier_prep)(struct nfp_app *app, struct nfp_net *nn, @@ -277,13 +275,6 @@ static inline bool nfp_app_has_tc(struct nfp_app *app) return app && app->type->setup_tc; } -static inline bool nfp_app_tc_busy(struct nfp_app *app, struct nfp_net *nn) -{ - if (!app || !app->type->tc_busy) - return false; - return app->type->tc_busy(app, nn); -} - static inline int nfp_app_setup_tc(struct nfp_app *app, struct net_device *netdev, enum tc_setup_type type, void *type_data) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 9290e75f6e30..e4a9ff7a7c17 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3175,10 +3175,9 @@ static int nfp_net_set_features(struct net_device *netdev, new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER; } - if (changed & NETIF_F_HW_TC && nfp_app_tc_busy(nn->app, nn)) { - nn_err(nn, "Cannot disable HW TC offload while in use\n"); - return -EBUSY; - } + err = nfp_port_set_features(netdev, features); + if (err) + return err; nn_dbg(nn, "Feature change 0x%llx -> 0x%llx (changed=0x%llx)\n", netdev->features, features, changed); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 78b36c67c232..5a7174efacb2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -250,6 +250,7 @@ const struct net_device_ops nfp_repr_netdev_ops = { .ndo_set_vf_spoofchk = nfp_app_set_vf_spoofchk, .ndo_get_vf_config = nfp_app_get_vf_config, .ndo_set_vf_link_state = nfp_app_set_vf_link_state, + .ndo_set_features = nfp_port_set_features, }; static void nfp_repr_clean(struct nfp_repr *repr) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 34a6e035fe9a..7bd8be5c833b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -32,6 +32,7 @@ */ #include +#include #include #include "nfpcore/nfp_cpp.h" @@ -100,6 +101,23 @@ int nfp_port_setup_tc(struct net_device *netdev, enum tc_setup_type type, return nfp_app_setup_tc(port->app, netdev, type, type_data); } +int nfp_port_set_features(struct net_device *netdev, netdev_features_t features) +{ + struct nfp_port *port; + + port = nfp_port_from_netdev(netdev); + if (!port) + return 0; + + if ((netdev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) && + port->tc_offload_cnt) { + netdev_err(netdev, "Cannot disable HW TC offload while offloads active\n"); + return -EBUSY; + } + + return 0; +} + struct nfp_port * nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 21bd4aa32646..fa7e669a969c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -72,6 +72,8 @@ enum nfp_port_flags { * @netdev: backpointer to associated netdev * @type: what port type does the entity represent * @flags: port flags + * @tc_offload_cnt: number of active TC offloads, how offloads are counted + * is not defined, use as a boolean * @app: backpointer to the app structure * @dl_port: devlink port structure * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme @@ -87,6 +89,7 @@ struct nfp_port { enum nfp_port_type type; unsigned long flags; + unsigned long tc_offload_cnt; struct nfp_app *app; @@ -121,6 +124,9 @@ static inline bool nfp_port_is_vnic(const struct nfp_port *port) return port->type == NFP_PORT_PF_PORT || port->type == NFP_PORT_VF_PORT; } +int +nfp_port_set_features(struct net_device *netdev, netdev_features_t features); + struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); struct nfp_port * nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id);