From patchwork Wed Feb 3 11:45:25 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 577853 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id EE8B3140556 for ; Wed, 3 Feb 2016 22:46:30 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b=Z64XaZa6; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756723AbcBCLqO (ORCPT ); Wed, 3 Feb 2016 06:46:14 -0500 Received: from mail-wm0-f44.google.com ([74.125.82.44]:35303 "EHLO mail-wm0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933137AbcBCLpy (ORCPT ); Wed, 3 Feb 2016 06:45:54 -0500 Received: by mail-wm0-f44.google.com with SMTP id r129so160916326wmr.0 for ; Wed, 03 Feb 2016 03:45:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=yttdDtBOPRfMcJYlBxpjsMz0ZKd9Q4QD8+arNY4uhVo=; b=Z64XaZa6Z9eQH6mnGaS3Rtc1aMPhu1X8oAcmAOI4SCmDt0+NmbdiHw4XCei8nbFX1B I6no08vLg1T1Jnr7+vPrtO6RnjGv0rg9x2wsJW2s9hT7vxlaq6KryEA6+oBaCObrse93 JN0MN7egnK59DhZ79wm3+0Pw0P23szQF7TOjpBw5vnO1we83QBGb9itQdA5wmYOI7B9U NK1FN3fzR8UiLps3B078YeFM6UbMtVdDuUkmeczlegxaxbXJy/fNwd3Dm4Y5+8F5/Cqz 9EyDW1cuf2jgsO8vyfJCvOxM0WeNN5aPMZzJADbM7Mi2rc/sslfLcda2lNP0tmfYJ63E JH4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=yttdDtBOPRfMcJYlBxpjsMz0ZKd9Q4QD8+arNY4uhVo=; b=R4KL6OCBPY4Z3xydvyJhxc99clJHFDNvW/d1ZpZmhwXvp28G39Amo6PM8y/o7q3hzw sW7NCBpa+YpsHWJYbhvyV/7p2SSX87LBgkYKUrKUfPANi0m4eM7hB12B6R1WJ1qWERgR 7tGFXwvr55UeqEz9ws0l50fLIWwNXweoSzPOFH5Q5HkqHGyzhMnKi1W3VYhI/uXw1T5/ 7P1eZcVHcQSDpROx5iBoO7Vk/xqJzj7DX49iq75ZP7c8cJt+FZfeU2WTIs7QsLX+VHmx Hcs5I2Dnvm7dhU157BAy9AzUkQMRdqvjQZHXxbHwakG0ywIFkJBO7XGxptP/SCBCtnVi FRnQ== X-Gm-Message-State: AG10YOR4ACfQOzBLzEgcp7dOUldqOBMLlp3dhS8+OPfTTVJ6YigPvddn0bFvE26iST9MEoPt X-Received: by 10.194.189.71 with SMTP id gg7mr1348430wjc.127.1454499953608; Wed, 03 Feb 2016 03:45:53 -0800 (PST) Received: from jkicinski-Precision-T1700.netronome.com (host217-39-174-19.in-addr.btopenworld.com. [217.39.174.19]) by smtp.gmail.com with ESMTPSA id gb9sm6084421wjb.26.2016.02.03.03.45.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 03 Feb 2016 03:45:52 -0800 (PST) From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, Jakub Kicinski Subject: [RFC (v3) 19/19] nfp: allow ring size reconfiguration at runtime Date: Wed, 3 Feb 2016 11:45:25 +0000 Message-Id: <1454499925-16359-20-git-send-email-jakub.kicinski@netronome.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1454499925-16359-1-git-send-email-jakub.kicinski@netronome.com> References: <1454499925-16359-1-git-send-email-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Since much of the required changes have already been made for changing MTU at runtime let's use it for ring size changes as well. Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 1 + .../net/ethernet/netronome/nfp/nfp_net_common.c | 129 +++++++++++++++++++++ .../net/ethernet/netronome/nfp/nfp_net_ethtool.c | 30 ++--- 3 files changed, 139 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 1e08c9cf3ee0..90ad6264e62c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -724,6 +724,7 @@ void nfp_net_rss_write_key(struct nfp_net *nn); void nfp_net_coalesce_write_cfg(struct nfp_net *nn); int nfp_net_irqs_alloc(struct nfp_net *nn); void nfp_net_irqs_disable(struct nfp_net *nn); +int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt); #ifdef CONFIG_NFP_NET_DEBUG void nfp_net_debugfs_create(void); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 2c86a10abcd3..70d366bdd4b7 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1442,6 +1442,59 @@ err_alloc: return -ENOMEM; } +static struct nfp_net_tx_ring * +nfp_net_shadow_tx_rings_prepare(struct nfp_net *nn, u32 buf_cnt) +{ + struct nfp_net_tx_ring *rings; + unsigned int r; + + rings = kcalloc(nn->num_tx_rings, sizeof(*rings), GFP_KERNEL); + if (!rings) + return NULL; + + for (r = 0; r < nn->num_tx_rings; r++) { + nfp_net_tx_ring_init(&rings[r], nn->tx_rings[r].r_vec, r); + + if (nfp_net_tx_ring_alloc(&rings[r], buf_cnt)) + goto err_free_prev; + } + + return rings; + +err_free_prev: + while (r--) + nfp_net_tx_ring_free(&rings[r]); + kfree(rings); + return NULL; +} + +static struct nfp_net_tx_ring * +nfp_net_shadow_tx_rings_swap(struct nfp_net *nn, struct nfp_net_tx_ring *rings) +{ + struct nfp_net_tx_ring *old = nn->tx_rings; + unsigned int r; + + for (r = 0; r < nn->num_tx_rings; r++) + old[r].r_vec->tx_ring = &rings[r]; + + nn->tx_rings = rings; + return old; +} + +static void +nfp_net_shadow_tx_rings_free(struct nfp_net *nn, struct nfp_net_tx_ring *rings) +{ + unsigned int r; + + if (!rings) + return; + + for (r = 0; r < nn->num_tx_rings; r++) + nfp_net_tx_ring_free(&rings[r]); + + kfree(rings); +} + /** * nfp_net_rx_ring_free() - Free resources allocated to a RX ring * @rx_ring: RX ring to free @@ -1558,6 +1611,9 @@ nfp_net_shadow_rx_rings_free(struct nfp_net *nn, struct nfp_net_rx_ring *rings) { unsigned int r; + if (!rings) + return; + for (r = 0; r < nn->num_r_vecs; r++) { nfp_net_rx_ring_bufs_free(nn, &rings[r]); nfp_net_rx_ring_free(&rings[r]); @@ -2100,6 +2156,79 @@ static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu) return err; } +int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt) +{ + struct nfp_net_tx_ring *tx_rings = NULL; + struct nfp_net_rx_ring *rx_rings = NULL; + u32 old_rxd_cnt, old_txd_cnt; + int err, err2; + + if (!(nn->ctrl & NFP_NET_CFG_CTRL_ENABLE)) { + nn->rxd_cnt = rxd_cnt; + nn->txd_cnt = txd_cnt; + return 0; + } + + old_rxd_cnt = nn->rxd_cnt; + old_txd_cnt = nn->txd_cnt; + + /* Prepare new rings */ + if (nn->rxd_cnt != rxd_cnt) { + rx_rings = nfp_net_shadow_rx_rings_prepare(nn, nn->fl_bufsz, + rxd_cnt); + if (!rx_rings) + return -ENOMEM; + } + if (nn->txd_cnt != txd_cnt) { + tx_rings = nfp_net_shadow_tx_rings_prepare(nn, txd_cnt); + if (!tx_rings) { + nfp_net_shadow_rx_rings_free(nn, rx_rings); + return -ENOMEM; + } + } + + /* Stop device, swap in new rings, try to start the device */ + nfp_net_close_stack(nn); + nfp_net_clear_config_and_disable(nn); + + if (rx_rings) + rx_rings = nfp_net_shadow_rx_rings_swap(nn, rx_rings); + if (tx_rings) + tx_rings = nfp_net_shadow_tx_rings_swap(nn, tx_rings); + + nn->rxd_cnt = rxd_cnt; + nn->txd_cnt = txd_cnt; + + err = nfp_net_set_config_and_enable(nn); + if (err) { + /* Try with old configuration and old rings */ + if (rx_rings) + rx_rings = nfp_net_shadow_rx_rings_swap(nn, rx_rings); + if (tx_rings) + tx_rings = nfp_net_shadow_tx_rings_swap(nn, tx_rings); + + nn->rxd_cnt = old_rxd_cnt; + nn->txd_cnt = old_txd_cnt; + + err2 = nfp_net_set_config_and_enable(nn); + if (err2) { + nn_err(nn, "Can't restore ring config - FW communication failed (%d,%d)\n", + err, err2); + nfp_net_shadow_rx_rings_free(nn, rx_rings); + nfp_net_shadow_tx_rings_free(nn, tx_rings); + nfp_net_close_free_all(nn); + return err2; + } + } + + nfp_net_shadow_rx_rings_free(nn, rx_rings); + nfp_net_shadow_tx_rings_free(nn, tx_rings); + + nfp_net_open_stack(nn); + + return err; +} + static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev, struct rtnl_link_stats64 *stats) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 9a4084a68db5..ccfef1f17627 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -153,37 +153,25 @@ static int nfp_net_set_ringparam(struct net_device *netdev, struct nfp_net *nn = netdev_priv(netdev); u32 rxd_cnt, txd_cnt; - if (netif_running(netdev)) { - /* Some NIC drivers allow reconfiguration on the fly, - * some down the interface, change and then up it - * again. For now we don't allow changes when the - * device is up. - */ - nn_warn(nn, "Can't change rings while device is up\n"); - return -EBUSY; - } - /* We don't have separate queues/rings for small/large frames. */ if (ring->rx_mini_pending || ring->rx_jumbo_pending) return -EINVAL; /* Round up to supported values */ rxd_cnt = roundup_pow_of_two(ring->rx_pending); - rxd_cnt = max_t(u32, rxd_cnt, NFP_NET_MIN_RX_DESCS); - rxd_cnt = min_t(u32, rxd_cnt, NFP_NET_MAX_RX_DESCS); - txd_cnt = roundup_pow_of_two(ring->tx_pending); - txd_cnt = max_t(u32, txd_cnt, NFP_NET_MIN_TX_DESCS); - txd_cnt = min_t(u32, txd_cnt, NFP_NET_MAX_TX_DESCS); - if (nn->rxd_cnt != rxd_cnt || nn->txd_cnt != txd_cnt) - nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n", - nn->rxd_cnt, rxd_cnt, nn->txd_cnt, txd_cnt); + if (rxd_cnt < NFP_NET_MIN_RX_DESCS || rxd_cnt > NFP_NET_MAX_RX_DESCS || + txd_cnt < NFP_NET_MIN_TX_DESCS || txd_cnt > NFP_NET_MAX_TX_DESCS) + return -EINVAL; - nn->rxd_cnt = rxd_cnt; - nn->txd_cnt = txd_cnt; + if (nn->rxd_cnt == rxd_cnt && nn->txd_cnt == txd_cnt) + return 0; - return 0; + nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n", + nn->rxd_cnt, rxd_cnt, nn->txd_cnt, txd_cnt); + + return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt); } static void nfp_net_get_strings(struct net_device *netdev,