aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2016-04-07 14:39:46 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-08 15:26:06 -0400
commit36a857e4f2c9783cd573c948df022011cb386aa4 (patch)
treedc88f6af30455d744501fb191019f6ad78dc3bab /drivers/net/ethernet
parent30d2117191b7437b5b6ce2f09eddf86f203c7a37 (diff)
nfp: convert .ndo_change_mtu() to prepare/commit paradigm
When changing MTU on running device first allocate new rings and buffers and once it succeeds proceed with changing MTU. Allocation of new rings is not really necessary for this operation - it's done to keep the code simple and because size of the extra ring memory is quite small compared to the size of buffers. Operation can still fail midway through if FW communication times out. In that case we retry with old MTU (rings). Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c108
1 files changed, 102 insertions, 6 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 03c60f755de0..e7c420fdcb0d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -1506,6 +1506,64 @@ err_alloc:
1506 return -ENOMEM; 1506 return -ENOMEM;
1507} 1507}
1508 1508
1509static struct nfp_net_rx_ring *
1510nfp_net_shadow_rx_rings_prepare(struct nfp_net *nn, unsigned int fl_bufsz)
1511{
1512 struct nfp_net_rx_ring *rings;
1513 unsigned int r;
1514
1515 rings = kcalloc(nn->num_rx_rings, sizeof(*rings), GFP_KERNEL);
1516 if (!rings)
1517 return NULL;
1518
1519 for (r = 0; r < nn->num_rx_rings; r++) {
1520 nfp_net_rx_ring_init(&rings[r], nn->rx_rings[r].r_vec, r);
1521
1522 if (nfp_net_rx_ring_alloc(&rings[r], fl_bufsz))
1523 goto err_free_prev;
1524
1525 if (nfp_net_rx_ring_bufs_alloc(nn, &rings[r]))
1526 goto err_free_ring;
1527 }
1528
1529 return rings;
1530
1531err_free_prev:
1532 while (r--) {
1533 nfp_net_rx_ring_bufs_free(nn, &rings[r]);
1534err_free_ring:
1535 nfp_net_rx_ring_free(&rings[r]);
1536 }
1537 kfree(rings);
1538 return NULL;
1539}
1540
1541static struct nfp_net_rx_ring *
1542nfp_net_shadow_rx_rings_swap(struct nfp_net *nn, struct nfp_net_rx_ring *rings)
1543{
1544 struct nfp_net_rx_ring *old = nn->rx_rings;
1545 unsigned int r;
1546
1547 for (r = 0; r < nn->num_rx_rings; r++)
1548 old[r].r_vec->rx_ring = &rings[r];
1549
1550 nn->rx_rings = rings;
1551 return old;
1552}
1553
1554static void
1555nfp_net_shadow_rx_rings_free(struct nfp_net *nn, struct nfp_net_rx_ring *rings)
1556{
1557 unsigned int r;
1558
1559 for (r = 0; r < nn->num_r_vecs; r++) {
1560 nfp_net_rx_ring_bufs_free(nn, &rings[r]);
1561 nfp_net_rx_ring_free(&rings[r]);
1562 }
1563
1564 kfree(rings);
1565}
1566
1509static int 1567static int
1510nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, 1568nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
1511 int idx) 1569 int idx)
@@ -1984,23 +2042,61 @@ static void nfp_net_set_rx_mode(struct net_device *netdev)
1984 2042
1985static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu) 2043static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu)
1986{ 2044{
2045 unsigned int old_mtu, old_fl_bufsz, new_fl_bufsz;
1987 struct nfp_net *nn = netdev_priv(netdev); 2046 struct nfp_net *nn = netdev_priv(netdev);
2047 struct nfp_net_rx_ring *tmp_rings;
2048 int err;
1988 2049
1989 if (new_mtu < 68 || new_mtu > nn->max_mtu) { 2050 if (new_mtu < 68 || new_mtu > nn->max_mtu) {
1990 nn_err(nn, "New MTU (%d) is not valid\n", new_mtu); 2051 nn_err(nn, "New MTU (%d) is not valid\n", new_mtu);
1991 return -EINVAL; 2052 return -EINVAL;
1992 } 2053 }
1993 2054
2055 old_mtu = netdev->mtu;
2056 old_fl_bufsz = nn->fl_bufsz;
2057 new_fl_bufsz = NFP_NET_MAX_PREPEND + ETH_HLEN + VLAN_HLEN * 2 + new_mtu;
2058
2059 if (!netif_running(netdev)) {
2060 netdev->mtu = new_mtu;
2061 nn->fl_bufsz = new_fl_bufsz;
2062 return 0;
2063 }
2064
2065 /* Prepare new rings */
2066 tmp_rings = nfp_net_shadow_rx_rings_prepare(nn, new_fl_bufsz);
2067 if (!tmp_rings)
2068 return -ENOMEM;
2069
2070 /* Stop device, swap in new rings, try to start the firmware */
2071 nfp_net_close_stack(nn);
2072 nfp_net_clear_config_and_disable(nn);
2073
2074 tmp_rings = nfp_net_shadow_rx_rings_swap(nn, tmp_rings);
2075
1994 netdev->mtu = new_mtu; 2076 netdev->mtu = new_mtu;
1995 nn->fl_bufsz = NFP_NET_MAX_PREPEND + ETH_HLEN + VLAN_HLEN * 2 + new_mtu; 2077 nn->fl_bufsz = new_fl_bufsz;
2078
2079 err = nfp_net_set_config_and_enable(nn);
2080 if (err) {
2081 const int err_new = err;
2082
2083 /* Try with old configuration and old rings */
2084 tmp_rings = nfp_net_shadow_rx_rings_swap(nn, tmp_rings);
2085
2086 netdev->mtu = old_mtu;
2087 nn->fl_bufsz = old_fl_bufsz;
1996 2088
1997 /* restart if running */ 2089 err = __nfp_net_set_config_and_enable(nn);
1998 if (netif_running(netdev)) { 2090 if (err)
1999 nfp_net_netdev_close(netdev); 2091 nn_err(nn, "Can't restore MTU - FW communication failed (%d,%d)\n",
2000 nfp_net_netdev_open(netdev); 2092 err_new, err);
2001 } 2093 }
2002 2094
2003 return 0; 2095 nfp_net_shadow_rx_rings_free(nn, tmp_rings);
2096
2097 nfp_net_open_stack(nn);
2098
2099 return err;
2004} 2100}
2005 2101
2006static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev, 2102static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev,