aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Hurley <john.hurley@netronome.com>2018-03-28 21:50:07 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-30 10:18:55 -0400
commit29a5dcae2790ba7fb26ea7128cbe61ecf906ab0a (patch)
treef9ce1b086110ad43f50eb0fb08d3a7bb4d689eef
parent167cebeffadd45ce1e786889ab9346c15d64389b (diff)
nfp: flower: offload phys port MTU change
Trigger a port mod message to request an MTU change on the NIC when any physical port representor is assigned a new MTU value. The driver waits 10 msec for an ack that the FW has set the MTU. If no ack is received the request is rejected and an appropriate warning flagged. Rather than maintain an MTU queue per repr, one is maintained per app. Because the MTU ndo is protected by the rtnl lock, there can never be contention here. Portmod messages from the NIC are also protected by rtnl so we first check if the portmod is an ack and, if so, handle outside rtnl and the cmsg work queue. Acks are detected by the marking of a bit in a portmod response. They are then verfied by checking the port number and MTU value expected by the app. If the expected MTU is 0 then no acks are currently expected. Also, ensure that the packet headroom reserved by the flower firmware is considered when accepting an MTU change on any repr. Signed-off-by: John Hurley <john.hurley@netronome.com> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/cmsg.c41
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/cmsg.h4
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/main.c87
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/main.h19
4 files changed, 146 insertions, 5 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
index baaea6f1a9d8..3735c09d2112 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
@@ -104,7 +104,8 @@ nfp_flower_cmsg_mac_repr_add(struct sk_buff *skb, unsigned int idx,
104 msg->ports[idx].phys_port = phys_port; 104 msg->ports[idx].phys_port = phys_port;
105} 105}
106 106
107int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok) 107int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok,
108 unsigned int mtu, bool mtu_only)
108{ 109{
109 struct nfp_flower_cmsg_portmod *msg; 110 struct nfp_flower_cmsg_portmod *msg;
110 struct sk_buff *skb; 111 struct sk_buff *skb;
@@ -118,7 +119,11 @@ int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok)
118 msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id); 119 msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id);
119 msg->reserved = 0; 120 msg->reserved = 0;
120 msg->info = carrier_ok; 121 msg->info = carrier_ok;
121 msg->mtu = cpu_to_be16(repr->netdev->mtu); 122
123 if (mtu_only)
124 msg->info |= NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY;
125
126 msg->mtu = cpu_to_be16(mtu);
122 127
123 nfp_ctrl_tx(repr->app->ctrl, skb); 128 nfp_ctrl_tx(repr->app->ctrl, skb);
124 129
@@ -146,6 +151,34 @@ int nfp_flower_cmsg_portreify(struct nfp_repr *repr, bool exists)
146 return 0; 151 return 0;
147} 152}
148 153
154static bool
155nfp_flower_process_mtu_ack(struct nfp_app *app, struct sk_buff *skb)
156{
157 struct nfp_flower_priv *app_priv = app->priv;
158 struct nfp_flower_cmsg_portmod *msg;
159
160 msg = nfp_flower_cmsg_get_data(skb);
161
162 if (!(msg->info & NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY))
163 return false;
164
165 spin_lock_bh(&app_priv->mtu_conf.lock);
166 if (!app_priv->mtu_conf.requested_val ||
167 app_priv->mtu_conf.portnum != be32_to_cpu(msg->portnum) ||
168 be16_to_cpu(msg->mtu) != app_priv->mtu_conf.requested_val) {
169 /* Not an ack for requested MTU change. */
170 spin_unlock_bh(&app_priv->mtu_conf.lock);
171 return false;
172 }
173
174 app_priv->mtu_conf.ack = true;
175 app_priv->mtu_conf.requested_val = 0;
176 wake_up(&app_priv->mtu_conf.wait_q);
177 spin_unlock_bh(&app_priv->mtu_conf.lock);
178
179 return true;
180}
181
149static void 182static void
150nfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb) 183nfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb)
151{ 184{
@@ -269,6 +302,10 @@ void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
269 /* We need to deal with stats updates from HW asap */ 302 /* We need to deal with stats updates from HW asap */
270 nfp_flower_rx_flow_stats(app, skb); 303 nfp_flower_rx_flow_stats(app, skb);
271 dev_consume_skb_any(skb); 304 dev_consume_skb_any(skb);
305 } else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_PORT_MOD &&
306 nfp_flower_process_mtu_ack(app, skb)) {
307 /* Handle MTU acks outside wq to prevent RTNL conflict. */
308 dev_consume_skb_any(skb);
272 } else { 309 } else {
273 skb_queue_tail(&priv->cmsg_skbs, skb); 310 skb_queue_tail(&priv->cmsg_skbs, skb);
274 schedule_work(&priv->cmsg_work); 311 schedule_work(&priv->cmsg_work);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
index 3f46d836d1b8..96bc0e33980c 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
@@ -397,6 +397,7 @@ struct nfp_flower_cmsg_portmod {
397}; 397};
398 398
399#define NFP_FLOWER_CMSG_PORTMOD_INFO_LINK BIT(0) 399#define NFP_FLOWER_CMSG_PORTMOD_INFO_LINK BIT(0)
400#define NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY BIT(1)
400 401
401/* NFP_FLOWER_CMSG_TYPE_PORT_REIFY */ 402/* NFP_FLOWER_CMSG_TYPE_PORT_REIFY */
402struct nfp_flower_cmsg_portreify { 403struct nfp_flower_cmsg_portreify {
@@ -464,7 +465,8 @@ void
464nfp_flower_cmsg_mac_repr_add(struct sk_buff *skb, unsigned int idx, 465nfp_flower_cmsg_mac_repr_add(struct sk_buff *skb, unsigned int idx,
465 unsigned int nbi, unsigned int nbi_port, 466 unsigned int nbi, unsigned int nbi_port,
466 unsigned int phys_port); 467 unsigned int phys_port);
467int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok); 468int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok,
469 unsigned int mtu, bool mtu_only);
468int nfp_flower_cmsg_portreify(struct nfp_repr *repr, bool exists); 470int nfp_flower_cmsg_portreify(struct nfp_repr *repr, bool exists);
469void nfp_flower_cmsg_process_rx(struct work_struct *work); 471void nfp_flower_cmsg_process_rx(struct work_struct *work);
470void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb); 472void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c
index 742d6f1575b5..6357e0720f43 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.c
@@ -52,6 +52,8 @@
52 52
53#define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL 53#define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL
54 54
55#define NFP_FLOWER_FRAME_HEADROOM 158
56
55static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn) 57static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn)
56{ 58{
57 return "FLOWER"; 59 return "FLOWER";
@@ -157,7 +159,7 @@ nfp_flower_repr_netdev_open(struct nfp_app *app, struct nfp_repr *repr)
157{ 159{
158 int err; 160 int err;
159 161
160 err = nfp_flower_cmsg_portmod(repr, true); 162 err = nfp_flower_cmsg_portmod(repr, true, repr->netdev->mtu, false);
161 if (err) 163 if (err)
162 return err; 164 return err;
163 165
@@ -171,7 +173,7 @@ nfp_flower_repr_netdev_stop(struct nfp_app *app, struct nfp_repr *repr)
171{ 173{
172 netif_tx_disable(repr->netdev); 174 netif_tx_disable(repr->netdev);
173 175
174 return nfp_flower_cmsg_portmod(repr, false); 176 return nfp_flower_cmsg_portmod(repr, false, repr->netdev->mtu, false);
175} 177}
176 178
177static int 179static int
@@ -521,6 +523,9 @@ static int nfp_flower_init(struct nfp_app *app)
521 INIT_WORK(&app_priv->cmsg_work, nfp_flower_cmsg_process_rx); 523 INIT_WORK(&app_priv->cmsg_work, nfp_flower_cmsg_process_rx);
522 init_waitqueue_head(&app_priv->reify_wait_queue); 524 init_waitqueue_head(&app_priv->reify_wait_queue);
523 525
526 init_waitqueue_head(&app_priv->mtu_conf.wait_q);
527 spin_lock_init(&app_priv->mtu_conf.lock);
528
524 err = nfp_flower_metadata_init(app); 529 err = nfp_flower_metadata_init(app);
525 if (err) 530 if (err)
526 goto err_free_app_priv; 531 goto err_free_app_priv;
@@ -552,6 +557,81 @@ static void nfp_flower_clean(struct nfp_app *app)
552 app->priv = NULL; 557 app->priv = NULL;
553} 558}
554 559
560static int
561nfp_flower_check_mtu(struct nfp_app *app, struct net_device *netdev,
562 int new_mtu)
563{
564 /* The flower fw reserves NFP_FLOWER_FRAME_HEADROOM bytes of the
565 * supported max MTU to allow for appending tunnel headers. To prevent
566 * unexpected behaviour this needs to be accounted for.
567 */
568 if (new_mtu > netdev->max_mtu - NFP_FLOWER_FRAME_HEADROOM) {
569 nfp_err(app->cpp, "New MTU (%d) is not valid\n", new_mtu);
570 return -EINVAL;
571 }
572
573 return 0;
574}
575
576static bool nfp_flower_check_ack(struct nfp_flower_priv *app_priv)
577{
578 bool ret;
579
580 spin_lock_bh(&app_priv->mtu_conf.lock);
581 ret = app_priv->mtu_conf.ack;
582 spin_unlock_bh(&app_priv->mtu_conf.lock);
583
584 return ret;
585}
586
587static int
588nfp_flower_repr_change_mtu(struct nfp_app *app, struct net_device *netdev,
589 int new_mtu)
590{
591 struct nfp_flower_priv *app_priv = app->priv;
592 struct nfp_repr *repr = netdev_priv(netdev);
593 int err, ack;
594
595 /* Only need to config FW for physical port MTU change. */
596 if (repr->port->type != NFP_PORT_PHYS_PORT)
597 return 0;
598
599 if (!(app_priv->flower_ext_feats & NFP_FL_NBI_MTU_SETTING)) {
600 nfp_err(app->cpp, "Physical port MTU setting not supported\n");
601 return -EINVAL;
602 }
603
604 spin_lock_bh(&app_priv->mtu_conf.lock);
605 app_priv->mtu_conf.ack = false;
606 app_priv->mtu_conf.requested_val = new_mtu;
607 app_priv->mtu_conf.portnum = repr->dst->u.port_info.port_id;
608 spin_unlock_bh(&app_priv->mtu_conf.lock);
609
610 err = nfp_flower_cmsg_portmod(repr, netif_carrier_ok(netdev), new_mtu,
611 true);
612 if (err) {
613 spin_lock_bh(&app_priv->mtu_conf.lock);
614 app_priv->mtu_conf.requested_val = 0;
615 spin_unlock_bh(&app_priv->mtu_conf.lock);
616 return err;
617 }
618
619 /* Wait for fw to ack the change. */
620 ack = wait_event_timeout(app_priv->mtu_conf.wait_q,
621 nfp_flower_check_ack(app_priv),
622 msecs_to_jiffies(10));
623
624 if (!ack) {
625 spin_lock_bh(&app_priv->mtu_conf.lock);
626 app_priv->mtu_conf.requested_val = 0;
627 spin_unlock_bh(&app_priv->mtu_conf.lock);
628 nfp_warn(app->cpp, "MTU change not verified with fw\n");
629 return -EIO;
630 }
631
632 return 0;
633}
634
555static int nfp_flower_start(struct nfp_app *app) 635static int nfp_flower_start(struct nfp_app *app)
556{ 636{
557 return nfp_tunnel_config_start(app); 637 return nfp_tunnel_config_start(app);
@@ -574,6 +654,9 @@ const struct nfp_app_type app_flower = {
574 .init = nfp_flower_init, 654 .init = nfp_flower_init,
575 .clean = nfp_flower_clean, 655 .clean = nfp_flower_clean,
576 656
657 .check_mtu = nfp_flower_check_mtu,
658 .repr_change_mtu = nfp_flower_repr_change_mtu,
659
577 .vnic_alloc = nfp_flower_vnic_alloc, 660 .vnic_alloc = nfp_flower_vnic_alloc,
578 .vnic_init = nfp_flower_vnic_init, 661 .vnic_init = nfp_flower_vnic_init,
579 .vnic_clean = nfp_flower_vnic_clean, 662 .vnic_clean = nfp_flower_vnic_clean,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index c5cebf6fb1d3..e030b3ce4510 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -65,6 +65,7 @@ struct nfp_app;
65 65
66/* Extra features bitmap. */ 66/* Extra features bitmap. */
67#define NFP_FL_FEATS_GENEVE BIT(0) 67#define NFP_FL_FEATS_GENEVE BIT(0)
68#define NFP_FL_NBI_MTU_SETTING BIT(1)
68 69
69struct nfp_fl_mask_id { 70struct nfp_fl_mask_id {
70 struct circ_buf mask_id_free_list; 71 struct circ_buf mask_id_free_list;
@@ -79,6 +80,22 @@ struct nfp_fl_stats_id {
79}; 80};
80 81
81/** 82/**
83 * struct nfp_mtu_conf - manage MTU setting
84 * @portnum: NFP port number of repr with requested MTU change
85 * @requested_val: MTU value requested for repr
86 * @ack: Received ack that MTU has been correctly set
87 * @wait_q: Wait queue for MTU acknowledgements
88 * @lock: Lock for setting/reading MTU variables
89 */
90struct nfp_mtu_conf {
91 u32 portnum;
92 unsigned int requested_val;
93 bool ack;
94 wait_queue_head_t wait_q;
95 spinlock_t lock;
96};
97
98/**
82 * struct nfp_flower_priv - Flower APP per-vNIC priv data 99 * struct nfp_flower_priv - Flower APP per-vNIC priv data
83 * @app: Back pointer to app 100 * @app: Back pointer to app
84 * @nn: Pointer to vNIC 101 * @nn: Pointer to vNIC
@@ -106,6 +123,7 @@ struct nfp_fl_stats_id {
106 * @reify_replies: atomically stores the number of replies received 123 * @reify_replies: atomically stores the number of replies received
107 * from firmware for repr reify 124 * from firmware for repr reify
108 * @reify_wait_queue: wait queue for repr reify response counting 125 * @reify_wait_queue: wait queue for repr reify response counting
126 * @mtu_conf: Configuration of repr MTU value
109 */ 127 */
110struct nfp_flower_priv { 128struct nfp_flower_priv {
111 struct nfp_app *app; 129 struct nfp_app *app;
@@ -133,6 +151,7 @@ struct nfp_flower_priv {
133 struct notifier_block nfp_tun_neigh_nb; 151 struct notifier_block nfp_tun_neigh_nb;
134 atomic_t reify_replies; 152 atomic_t reify_replies;
135 wait_queue_head_t reify_wait_queue; 153 wait_queue_head_t reify_wait_queue;
154 struct nfp_mtu_conf mtu_conf;
136}; 155};
137 156
138struct nfp_fl_key_ls { 157struct nfp_fl_key_ls {