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: 9208863 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A56076075F for ; Thu, 30 Jun 2016 19:06:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 93F6F28686 for ; Thu, 30 Jun 2016 19:06:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 83A612851E; Thu, 30 Jun 2016 19:06:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D68CD2851E for ; Thu, 30 Jun 2016 19:06:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752216AbcF3TF7 (ORCPT ); Thu, 30 Jun 2016 15:05:59 -0400 Received: from mail-lf0-f52.google.com ([209.85.215.52]:33403 "EHLO mail-lf0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752202AbcF3TEx (ORCPT ); Thu, 30 Jun 2016 15:04:53 -0400 Received: by mail-lf0-f52.google.com with SMTP id f6so62165289lfg.0 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=CvLpHW3BHiyWuCpJ8MirKMqBbraVCMRQdFcxNmkCNsl+GvXX5Ao5aM7ByFSAqUKTne hRbQmMg9JVEVrIjBHojhcUQ+yK00e7UQIQD2dpK4yjbKFYuWzBO2TlM62CoPWZY7PWiQ Xav0u6bJKV/13hhUV81RMdHrUI817Et+b37HgrWnZkL9nui6YmuRH6f0v0fp9oY1AV+R DDfYQGKdfQw40x97+aC9BARoslG2loeHstTZSvR4Ki9RXvhKPwf2VRGommA1O+bc11ZJ SdLmExKDWGOF0MxMX9KF7mk7FoE9maAhTs1CUPe+wybiPYLXQEg5yq+cpYWKrkVKupqy Z6Eg== X-Gm-Message-State: ALyK8tLOxAkZfubsIComJRtBi5IX1g2gurPrvUTEEm9EeHBd0Mn4p36oFZN5qXkJix1VhI+X 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: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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(+) 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,