summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
diff options
context:
space:
mode:
authorJohn Hurley <john.hurley@netronome.com>2018-03-28 18:50:07 -0700
committerDavid S. Miller <davem@davemloft.net>2018-03-30 10:18:55 -0400
commit29a5dcae2790ba7fb26ea7128cbe61ecf906ab0a (patch)
treef9ce1b086110ad43f50eb0fb08d3a7bb4d689eef /drivers/net/ethernet/netronome/nfp/flower/cmsg.c
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>
Diffstat (limited to 'drivers/net/ethernet/netronome/nfp/flower/cmsg.c')
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/cmsg.c41
1 files changed, 39 insertions, 2 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,
msg->ports[idx].phys_port = phys_port;
}
-int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok)
+int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok,
+ unsigned int mtu, bool mtu_only)
{
struct nfp_flower_cmsg_portmod *msg;
struct sk_buff *skb;
@@ -118,7 +119,11 @@ int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok)
msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id);
msg->reserved = 0;
msg->info = carrier_ok;
- msg->mtu = cpu_to_be16(repr->netdev->mtu);
+
+ if (mtu_only)
+ msg->info |= NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY;
+
+ msg->mtu = cpu_to_be16(mtu);
nfp_ctrl_tx(repr->app->ctrl, skb);
@@ -146,6 +151,34 @@ int nfp_flower_cmsg_portreify(struct nfp_repr *repr, bool exists)
return 0;
}
+static bool
+nfp_flower_process_mtu_ack(struct nfp_app *app, struct sk_buff *skb)
+{
+ struct nfp_flower_priv *app_priv = app->priv;
+ struct nfp_flower_cmsg_portmod *msg;
+
+ msg = nfp_flower_cmsg_get_data(skb);
+
+ if (!(msg->info & NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY))
+ return false;
+
+ spin_lock_bh(&app_priv->mtu_conf.lock);
+ if (!app_priv->mtu_conf.requested_val ||
+ app_priv->mtu_conf.portnum != be32_to_cpu(msg->portnum) ||
+ be16_to_cpu(msg->mtu) != app_priv->mtu_conf.requested_val) {
+ /* Not an ack for requested MTU change. */
+ spin_unlock_bh(&app_priv->mtu_conf.lock);
+ return false;
+ }
+
+ app_priv->mtu_conf.ack = true;
+ app_priv->mtu_conf.requested_val = 0;
+ wake_up(&app_priv->mtu_conf.wait_q);
+ spin_unlock_bh(&app_priv->mtu_conf.lock);
+
+ return true;
+}
+
static void
nfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb)
{
@@ -269,6 +302,10 @@ void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
/* We need to deal with stats updates from HW asap */
nfp_flower_rx_flow_stats(app, skb);
dev_consume_skb_any(skb);
+ } else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_PORT_MOD &&
+ nfp_flower_process_mtu_ack(app, skb)) {
+ /* Handle MTU acks outside wq to prevent RTNL conflict. */
+ dev_consume_skb_any(skb);
} else {
skb_queue_tail(&priv->cmsg_skbs, skb);
schedule_work(&priv->cmsg_work);