From patchwork Thu Jun 30 19:04:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Khoronzhuk X-Patchwork-Id: 71270 Delivered-To: patch@linaro.org Received: by 10.140.28.4 with SMTP id 4csp546812qgy; Thu, 30 Jun 2016 12:05:26 -0700 (PDT) X-Received: by 10.98.93.216 with SMTP id n85mr24213756pfj.36.1467313519923; Thu, 30 Jun 2016 12:05:19 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t19si5643643pal.39.2016.06.30.12.05.19; Thu, 30 Jun 2016 12:05:19 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752411AbcF3TFF (ORCPT + 4 others); Thu, 30 Jun 2016 15:05:05 -0400 Received: from mail-lf0-f43.google.com ([209.85.215.43]:36520 "EHLO mail-lf0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752252AbcF3TE6 (ORCPT ); Thu, 30 Jun 2016 15:04:58 -0400 Received: by mail-lf0-f43.google.com with SMTP id q132so62142441lfe.3 for ; Thu, 30 Jun 2016 12:04:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=V86osYn1dvd91F7xxiAEChCX2XYdeKOoj9T2QL8cvdc=; b=an63+dQ51hrAsV+3jk+OC3xmflGketUffIFL7NGC/tlCBPvC0e1TaJ8teb4E97gWon ITOKam5750nHg26s3XGlQFvdC/4h5DYnBZHwwERV/R16nDv6rleUD99/4sUQ8+aIuHQ1 pToBbSft91NuHBBK7VhGgZ2UUJiWFWJtPUHc0= 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=V86osYn1dvd91F7xxiAEChCX2XYdeKOoj9T2QL8cvdc=; b=QdnWjV6V/asjjyBs3a6ja+EJIatjdZi6g0oYko000OV4lcKTw5gnF8GGkZzVzlmDUk Qhy29Ucwny0HOVL0CcFOV3TzvoNquSHsrrF7VfZMSn3+EW8218GhbvZ5mzi0oke0OkL7 /z9uIVwiJq6GEpJTLSlr+3mL5xQPCfKHZ4j6SOqefJdQLtab7JuHTL7+/yF+Ctcf0hGl Q8BkzaWun4TnQXePjutT6rUF1TCeHVQRwUQ0kNEHIsTDOYb3c8Rc2lDT9+UXyTDn9SAC fvG3Xk2yA1B0WI2KjkK453xluypPihb6vg4CylxSGIDBDAMoK+aU4mrOey44+Y7YtIoJ m3gA== X-Gm-Message-State: ALyK8tKmBFu0ISxR48c0xAN8uC1pqHsUPyD6Y9QFsi7B/njWu7yd28jmClwxW7bktFIMAVc7 X-Received: by 10.25.44.85 with SMTP id s82mr6140977lfs.197.1467313491278; Thu, 30 Jun 2016 12:04:51 -0700 (PDT) Received: from localhost.localdomain ([212.90.63.58]) by smtp.gmail.com with ESMTPSA id 195sm1745215ljf.40.2016.06.30.12.04.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 30 Jun 2016 12:04:50 -0700 (PDT) From: Ivan Khoronzhuk To: davem@davemloft.net, netdev@vger.kernel.org, mugunthanvnm@ti.com Cc: grygorii.strashko@ti.com, linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, nsekhar@ti.com, Ivan Khoronzhuk Subject: [PATCH 4/4] net: ethernet: ti: cpsw: add ethtool channels support Date: Thu, 30 Jun 2016 22:04:38 +0300 Message-Id: <1467313478-22919-5-git-send-email-ivan.khoronzhuk@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1467313478-22919-1-git-send-email-ivan.khoronzhuk@linaro.org> References: <1467313478-22919-1-git-send-email-ivan.khoronzhuk@linaro.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org These ops allow to control number of channels driver is allowed to work with. The maximum number of channels is 8 for rx and 8 for tx. After this patch the following commands are possible: $ ethtool -l eth0 $ ethtool -L eth0 rx 6 tx 6 Signed-off-by: Ivan Khoronzhuk --- drivers/net/ethernet/ti/cpsw.c | 188 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) -- 1.9.1 diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 595ed56..729b8be 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -740,6 +740,11 @@ static void cpsw_rx_handler(void *token, int len, int status) } requeue: + if (netif_dormant(ndev)) { + dev_kfree_skb_any(new_skb); + return; + } + ch = priv->rxch[skb_get_queue_mapping(new_skb)]; ret = cpdma_chan_submit(ch, new_skb, new_skb->data, skb_tailroom(new_skb), 0); @@ -2077,6 +2082,187 @@ static void cpsw_ethtool_op_complete(struct net_device *ndev) cpsw_err(priv, drv, "ethtool complete failed %d\n", ret); } +static void cpsw_get_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct cpsw_priv *priv = netdev_priv(dev); + + ch->max_combined = 0; + ch->max_rx = CPSW_MAX_QUEUES; + ch->max_tx = CPSW_MAX_QUEUES; + ch->max_other = 0; + ch->other_count = 0; + ch->rx_count = priv->rx_ch_num; + ch->tx_count = priv->tx_ch_num; + ch->combined_count = 0; +} + +static int cpsw_check_ch_settings(struct cpsw_priv *priv, + struct ethtool_channels *ch) +{ + if (ch->combined_count) + return -EINVAL; + + /* verify we have at least one channel in each direction */ + if (!ch->rx_count || !ch->tx_count) + return -EINVAL; + + if (ch->rx_count > priv->data.channels || + ch->tx_count > priv->data.channels) + return -EINVAL; + + return 0; +} + +static void cpsw_sync_dual_ch_list(struct net_device *sdev, + struct net_device *ddev) +{ + struct cpsw_priv *priv_s, *priv_d; + int i; + + priv_s = netdev_priv(sdev); + priv_d = netdev_priv(ddev); + + priv_d->rx_ch_num = priv_s->rx_ch_num; + priv_d->tx_ch_num = priv_s->tx_ch_num; + + for (i = 0; i < priv_d->tx_ch_num; i++) + priv_d->txch[i] = priv_s->txch[i]; + for (i = 0; i < priv_d->rx_ch_num; i++) + priv_d->rxch[i] = priv_s->rxch[i]; +} + +static int cpsw_update_channels_res(struct cpsw_priv *priv, int ch_num, int rx) +{ + int (*poll)(struct napi_struct *, int); + void (*handler)(void *, int, int); + struct cpdma_chan **chan; + int *ch; + int ret; + + if (rx) { + ch = &priv->rx_ch_num; + chan = priv->rxch; + handler = cpsw_rx_handler; + poll = cpsw_rx_poll; + } else { + ch = &priv->tx_ch_num; + chan = priv->txch; + handler = cpsw_tx_handler; + poll = cpsw_tx_poll; + } + + while (*ch < ch_num) { + chan[*ch] = cpdma_chan_create(priv->dma, *ch, handler, rx); + + if (IS_ERR(chan[*ch])) + return PTR_ERR(chan[*ch]); + + if (!chan[*ch]) + return -EINVAL; + + dev_info(priv->dev, "created new %d %s channel\n", *ch, + (rx ? "rx" : "tx")); + (*ch)++; + } + + while (*ch > ch_num) { + int tch = *ch - 1; + + ret = cpdma_chan_destroy(chan[tch]); + if (ret) + return ret; + + dev_info(priv->dev, "destroyed %d %s channel\n", tch, + (rx ? "rx" : "tx")); + (*ch)--; + } + + return 0; +} + +static int cpsw_update_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct cpsw_priv *priv; + int ret; + + priv = netdev_priv(dev); + + ret = cpsw_update_channels_res(priv, ch->rx_count, 1); + if (ret) + return ret; + + ret = cpsw_update_channels_res(priv, ch->tx_count, 0); + if (ret) + return ret; + + if (priv->data.dual_emac) { + int i; + /* mirror channels for another SL */ + for (i = 0; i < priv->data.slaves; i++) { + if (priv->slaves[i].ndev == dev) + continue; + + cpsw_sync_dual_ch_list(dev, priv->slaves[i].ndev); + } + } + + return 0; +} + +static int cpsw_set_channels(struct net_device *ndev, + struct ethtool_channels *chs) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + int ret; + + ret = cpsw_check_ch_settings(priv, chs); + if (ret < 0) + return ret; + + if (netif_running(ndev)) { + netif_tx_stop_all_queues(ndev); + cpsw_intr_disable(priv); + netif_dormant_on(ndev); + cpdma_ctlr_stop(priv->dma); + } + + ret = cpsw_update_channels(ndev, chs); + if (ret) + goto err; + + if (netif_running(ndev)) { + /* inform stach about new count of queues */ + ret = netif_set_real_num_tx_queues(ndev, priv->tx_ch_num); + if (ret) { + dev_err(priv->dev, "cannot set real number of tx queues\n"); + goto err; + } + + ret = netif_set_real_num_rx_queues(ndev, priv->rx_ch_num); + if (ret) { + dev_err(priv->dev, "cannot set real number of rx queues\n"); + goto err; + } + + netif_dormant_off(ndev); + + if (cpsw_fill_rx_channels(ndev)) + goto err; + + cpdma_ctlr_start(priv->dma); + cpsw_intr_enable(priv); + netif_tx_start_all_queues(ndev); + } + + return 0; +err: + dev_err(priv->dev, "cannot update channels number, closing device\n"); + dev_close(ndev); + return ret; +} + static const struct ethtool_ops cpsw_ethtool_ops = { .get_drvinfo = cpsw_get_drvinfo, .get_msglevel = cpsw_get_msglevel, @@ -2098,6 +2284,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = { .get_regs = cpsw_get_regs, .begin = cpsw_ethtool_op_begin, .complete = cpsw_ethtool_op_complete, + .get_channels = cpsw_get_channels, + .set_channels = cpsw_set_channels, }; static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,