diff options
author | Jakub Kicinski <jakub.kicinski@netronome.com> | 2018-02-07 23:55:24 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-02-08 10:01:27 -0500 |
commit | d692403e5cf8008f31f5664a6f3ce3e65d54f458 (patch) | |
tree | 497dfc82655e28d9159888154ad9d23248f9d176 | |
parent | 0b9de4ca853b6ba2c92ff0b4602281001b166639 (diff) |
nfp: forbid disabling hw-tc-offload on representors while offload active
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 <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Tested-by: Pieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/bpf/main.c | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/flower/offload.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_app.h | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_port.c | 18 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_port.h | 6 |
7 files changed, 33 insertions, 21 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index 61898dda11cf..34e98aa6b956 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c | |||
@@ -182,6 +182,7 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type, | |||
182 | return err; | 182 | return err; |
183 | 183 | ||
184 | bv->tc_prog = cls_bpf->prog; | 184 | bv->tc_prog = cls_bpf->prog; |
185 | nn->port->tc_offload_cnt = !!bv->tc_prog; | ||
185 | return 0; | 186 | return 0; |
186 | } | 187 | } |
187 | 188 | ||
@@ -219,13 +220,6 @@ static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev, | |||
219 | } | 220 | } |
220 | } | 221 | } |
221 | 222 | ||
222 | static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn) | ||
223 | { | ||
224 | struct nfp_bpf_vnic *bv = nn->app_priv; | ||
225 | |||
226 | return !!bv->tc_prog; | ||
227 | } | ||
228 | |||
229 | static int | 223 | static int |
230 | nfp_bpf_change_mtu(struct nfp_app *app, struct net_device *netdev, int new_mtu) | 224 | nfp_bpf_change_mtu(struct nfp_app *app, struct net_device *netdev, int new_mtu) |
231 | { | 225 | { |
@@ -429,7 +423,6 @@ const struct nfp_app_type app_bpf = { | |||
429 | .ctrl_msg_rx = nfp_bpf_ctrl_msg_rx, | 423 | .ctrl_msg_rx = nfp_bpf_ctrl_msg_rx, |
430 | 424 | ||
431 | .setup_tc = nfp_bpf_setup_tc, | 425 | .setup_tc = nfp_bpf_setup_tc, |
432 | .tc_busy = nfp_bpf_tc_busy, | ||
433 | .bpf = nfp_ndo_bpf, | 426 | .bpf = nfp_ndo_bpf, |
434 | .xdp_offload = nfp_bpf_xdp_offload, | 427 | .xdp_offload = nfp_bpf_xdp_offload, |
435 | }; | 428 | }; |
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 08c4c6dc5f7f..eb5c13dea8f5 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c | |||
@@ -349,6 +349,7 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, | |||
349 | struct tc_cls_flower_offload *flow, bool egress) | 349 | struct tc_cls_flower_offload *flow, bool egress) |
350 | { | 350 | { |
351 | enum nfp_flower_tun_type tun_type = NFP_FL_TUNNEL_NONE; | 351 | enum nfp_flower_tun_type tun_type = NFP_FL_TUNNEL_NONE; |
352 | struct nfp_port *port = nfp_port_from_netdev(netdev); | ||
352 | struct nfp_flower_priv *priv = app->priv; | 353 | struct nfp_flower_priv *priv = app->priv; |
353 | struct nfp_fl_payload *flow_pay; | 354 | struct nfp_fl_payload *flow_pay; |
354 | struct nfp_fl_key_ls *key_layer; | 355 | struct nfp_fl_key_ls *key_layer; |
@@ -390,6 +391,7 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, | |||
390 | INIT_HLIST_NODE(&flow_pay->link); | 391 | INIT_HLIST_NODE(&flow_pay->link); |
391 | flow_pay->tc_flower_cookie = flow->cookie; | 392 | flow_pay->tc_flower_cookie = flow->cookie; |
392 | hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie); | 393 | hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie); |
394 | port->tc_offload_cnt++; | ||
393 | 395 | ||
394 | /* Deallocate flow payload when flower rule has been destroyed. */ | 396 | /* Deallocate flow payload when flower rule has been destroyed. */ |
395 | kfree(key_layer); | 397 | kfree(key_layer); |
@@ -421,6 +423,7 @@ static int | |||
421 | nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, | 423 | nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, |
422 | struct tc_cls_flower_offload *flow) | 424 | struct tc_cls_flower_offload *flow) |
423 | { | 425 | { |
426 | struct nfp_port *port = nfp_port_from_netdev(netdev); | ||
424 | struct nfp_fl_payload *nfp_flow; | 427 | struct nfp_fl_payload *nfp_flow; |
425 | int err; | 428 | int err; |
426 | 429 | ||
@@ -442,6 +445,7 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, | |||
442 | 445 | ||
443 | err_free_flow: | 446 | err_free_flow: |
444 | hash_del_rcu(&nfp_flow->link); | 447 | hash_del_rcu(&nfp_flow->link); |
448 | port->tc_offload_cnt--; | ||
445 | kfree(nfp_flow->action_data); | 449 | kfree(nfp_flow->action_data); |
446 | kfree(nfp_flow->mask_data); | 450 | kfree(nfp_flow->mask_data); |
447 | kfree(nfp_flow->unmasked_data); | 451 | 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 437964afa8ee..20546ae67909 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h | |||
@@ -92,7 +92,6 @@ extern const struct nfp_app_type app_flower; | |||
92 | * @stop: stop application logic | 92 | * @stop: stop application logic |
93 | * @ctrl_msg_rx: control message handler | 93 | * @ctrl_msg_rx: control message handler |
94 | * @setup_tc: setup TC ndo | 94 | * @setup_tc: setup TC ndo |
95 | * @tc_busy: TC HW offload busy (rules loaded) | ||
96 | * @bpf: BPF ndo offload-related calls | 95 | * @bpf: BPF ndo offload-related calls |
97 | * @xdp_offload: offload an XDP program | 96 | * @xdp_offload: offload an XDP program |
98 | * @eswitch_mode_get: get SR-IOV eswitch mode | 97 | * @eswitch_mode_get: get SR-IOV eswitch mode |
@@ -135,7 +134,6 @@ struct nfp_app_type { | |||
135 | 134 | ||
136 | int (*setup_tc)(struct nfp_app *app, struct net_device *netdev, | 135 | int (*setup_tc)(struct nfp_app *app, struct net_device *netdev, |
137 | enum tc_setup_type type, void *type_data); | 136 | enum tc_setup_type type, void *type_data); |
138 | bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn); | ||
139 | int (*bpf)(struct nfp_app *app, struct nfp_net *nn, | 137 | int (*bpf)(struct nfp_app *app, struct nfp_net *nn, |
140 | struct netdev_bpf *xdp); | 138 | struct netdev_bpf *xdp); |
141 | int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn, | 139 | int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn, |
@@ -301,13 +299,6 @@ static inline bool nfp_app_has_tc(struct nfp_app *app) | |||
301 | return app && app->type->setup_tc; | 299 | return app && app->type->setup_tc; |
302 | } | 300 | } |
303 | 301 | ||
304 | static inline bool nfp_app_tc_busy(struct nfp_app *app, struct nfp_net *nn) | ||
305 | { | ||
306 | if (!app || !app->type->tc_busy) | ||
307 | return false; | ||
308 | return app->type->tc_busy(app, nn); | ||
309 | } | ||
310 | |||
311 | static inline int nfp_app_setup_tc(struct nfp_app *app, | 302 | static inline int nfp_app_setup_tc(struct nfp_app *app, |
312 | struct net_device *netdev, | 303 | struct net_device *netdev, |
313 | enum tc_setup_type type, void *type_data) | 304 | 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 fe77ea8b656c..19e989239af7 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c | |||
@@ -3210,10 +3210,9 @@ static int nfp_net_set_features(struct net_device *netdev, | |||
3210 | new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER; | 3210 | new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER; |
3211 | } | 3211 | } |
3212 | 3212 | ||
3213 | if (changed & NETIF_F_HW_TC && nfp_app_tc_busy(nn->app, nn)) { | 3213 | err = nfp_port_set_features(netdev, features); |
3214 | nn_err(nn, "Cannot disable HW TC offload while in use\n"); | 3214 | if (err) |
3215 | return -EBUSY; | 3215 | return err; |
3216 | } | ||
3217 | 3216 | ||
3218 | nn_dbg(nn, "Feature change 0x%llx -> 0x%llx (changed=0x%llx)\n", | 3217 | nn_dbg(nn, "Feature change 0x%llx -> 0x%llx (changed=0x%llx)\n", |
3219 | netdev->features, features, changed); | 3218 | 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 f67da6bde9da..619570524d2a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | |||
@@ -265,6 +265,7 @@ const struct net_device_ops nfp_repr_netdev_ops = { | |||
265 | .ndo_set_vf_spoofchk = nfp_app_set_vf_spoofchk, | 265 | .ndo_set_vf_spoofchk = nfp_app_set_vf_spoofchk, |
266 | .ndo_get_vf_config = nfp_app_get_vf_config, | 266 | .ndo_get_vf_config = nfp_app_get_vf_config, |
267 | .ndo_set_vf_link_state = nfp_app_set_vf_link_state, | 267 | .ndo_set_vf_link_state = nfp_app_set_vf_link_state, |
268 | .ndo_set_features = nfp_port_set_features, | ||
268 | }; | 269 | }; |
269 | 270 | ||
270 | static void nfp_repr_clean(struct nfp_repr *repr) | 271 | 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 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/lockdep.h> | 34 | #include <linux/lockdep.h> |
35 | #include <linux/netdevice.h> | ||
35 | #include <net/switchdev.h> | 36 | #include <net/switchdev.h> |
36 | 37 | ||
37 | #include "nfpcore/nfp_cpp.h" | 38 | #include "nfpcore/nfp_cpp.h" |
@@ -100,6 +101,23 @@ int nfp_port_setup_tc(struct net_device *netdev, enum tc_setup_type type, | |||
100 | return nfp_app_setup_tc(port->app, netdev, type, type_data); | 101 | return nfp_app_setup_tc(port->app, netdev, type, type_data); |
101 | } | 102 | } |
102 | 103 | ||
104 | int nfp_port_set_features(struct net_device *netdev, netdev_features_t features) | ||
105 | { | ||
106 | struct nfp_port *port; | ||
107 | |||
108 | port = nfp_port_from_netdev(netdev); | ||
109 | if (!port) | ||
110 | return 0; | ||
111 | |||
112 | if ((netdev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) && | ||
113 | port->tc_offload_cnt) { | ||
114 | netdev_err(netdev, "Cannot disable HW TC offload while offloads active\n"); | ||
115 | return -EBUSY; | ||
116 | } | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
103 | struct nfp_port * | 121 | struct nfp_port * |
104 | nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id) | 122 | nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id) |
105 | { | 123 | { |
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 { | |||
72 | * @netdev: backpointer to associated netdev | 72 | * @netdev: backpointer to associated netdev |
73 | * @type: what port type does the entity represent | 73 | * @type: what port type does the entity represent |
74 | * @flags: port flags | 74 | * @flags: port flags |
75 | * @tc_offload_cnt: number of active TC offloads, how offloads are counted | ||
76 | * is not defined, use as a boolean | ||
75 | * @app: backpointer to the app structure | 77 | * @app: backpointer to the app structure |
76 | * @dl_port: devlink port structure | 78 | * @dl_port: devlink port structure |
77 | * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme | 79 | * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme |
@@ -87,6 +89,7 @@ struct nfp_port { | |||
87 | enum nfp_port_type type; | 89 | enum nfp_port_type type; |
88 | 90 | ||
89 | unsigned long flags; | 91 | unsigned long flags; |
92 | unsigned long tc_offload_cnt; | ||
90 | 93 | ||
91 | struct nfp_app *app; | 94 | struct nfp_app *app; |
92 | 95 | ||
@@ -121,6 +124,9 @@ static inline bool nfp_port_is_vnic(const struct nfp_port *port) | |||
121 | return port->type == NFP_PORT_PF_PORT || port->type == NFP_PORT_VF_PORT; | 124 | return port->type == NFP_PORT_PF_PORT || port->type == NFP_PORT_VF_PORT; |
122 | } | 125 | } |
123 | 126 | ||
127 | int | ||
128 | nfp_port_set_features(struct net_device *netdev, netdev_features_t features); | ||
129 | |||
124 | struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); | 130 | struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); |
125 | struct nfp_port * | 131 | struct nfp_port * |
126 | nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id); | 132 | nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id); |