From patchwork Thu Apr 13 04:39:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Herrenschmidt X-Patchwork-Id: 750266 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 3w3Skd0Hdpz9s2s for ; Thu, 13 Apr 2017 14:39:53 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751671AbdDMEjv (ORCPT ); Thu, 13 Apr 2017 00:39:51 -0400 Received: from gate.crashing.org ([63.228.1.57]:57828 "EHLO gate.crashing.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751438AbdDMEjt (ORCPT ); Thu, 13 Apr 2017 00:39:49 -0400 Received: from pasglop.ozlabs.ibm.com (localhost.localdomain [127.0.0.1]) by gate.crashing.org (8.14.1/8.13.8) with ESMTP id v3D4dO9j023336; Wed, 12 Apr 2017 23:39:29 -0500 From: Benjamin Herrenschmidt To: netdev@vger.kernel.org Cc: Benjamin Herrenschmidt Subject: [PATCH v2 2/9] ftgmac100: Add pause frames configuration and support Date: Thu, 13 Apr 2017 14:39:09 +1000 Message-Id: <20170413043916.7793-3-benh@kernel.crashing.org> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170413043916.7793-1-benh@kernel.crashing.org> References: <20170413043916.7793-1-benh@kernel.crashing.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Hopefully my understanding of how the hardware works is correct, as the documentation isn't completely clear. So far I have seen no obvious issue. Pause seem to also work with NC-SI. Signed-off-by: Benjamin Herrenschmidt --- drivers/net/ethernet/faraday/ftgmac100.c | 96 +++++++++++++++++++++++++++++++- drivers/net/ethernet/faraday/ftgmac100.h | 7 +++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 66a5065..4be8bf9 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -97,6 +97,11 @@ struct ftgmac100 { int cur_duplex; bool use_ncsi; + /* Flow control settings */ + bool tx_pause; + bool rx_pause; + bool aneg_pause; + /* Misc */ bool need_mac_restart; bool is_aspeed; @@ -217,6 +222,23 @@ static int ftgmac100_set_mac_addr(struct net_device *dev, void *p) return 0; } +static void ftgmac100_config_pause(struct ftgmac100 *priv) +{ + u32 fcr = FTGMAC100_FCR_PAUSE_TIME(16); + + /* Throttle tx queue when receiving pause frames */ + if (priv->rx_pause) + fcr |= FTGMAC100_FCR_FC_EN; + + /* Enables sending pause frames when the RX queue is past a + * certain threshold. + */ + if (priv->tx_pause) + fcr |= FTGMAC100_FCR_FCTHR_EN; + + iowrite32(fcr, priv->base + FTGMAC100_OFFSET_FCR); +} + static void ftgmac100_init_hw(struct ftgmac100 *priv) { u32 reg, rfifo_sz, tfifo_sz; @@ -910,6 +932,7 @@ static void ftgmac100_adjust_link(struct net_device *netdev) { struct ftgmac100 *priv = netdev_priv(netdev); struct phy_device *phydev = netdev->phydev; + bool tx_pause, rx_pause; int new_speed; /* We store "no link" as speed 0 */ @@ -918,8 +941,21 @@ static void ftgmac100_adjust_link(struct net_device *netdev) else new_speed = phydev->speed; + /* Grab pause settings from PHY if configured to do so */ + if (priv->aneg_pause) { + rx_pause = tx_pause = phydev->pause; + if (phydev->asym_pause) + tx_pause = !rx_pause; + } else { + rx_pause = priv->rx_pause; + tx_pause = priv->tx_pause; + } + + /* Link hasn't changed, do nothing */ if (phydev->speed == priv->cur_speed && - phydev->duplex == priv->cur_duplex) + phydev->duplex == priv->cur_duplex && + rx_pause == priv->rx_pause && + tx_pause == priv->tx_pause) return; /* Print status if we have a link or we had one and just lost it, @@ -930,6 +966,8 @@ static void ftgmac100_adjust_link(struct net_device *netdev) priv->cur_speed = new_speed; priv->cur_duplex = phydev->duplex; + priv->rx_pause = rx_pause; + priv->tx_pause = tx_pause; /* Link is down, do nothing else */ if (!new_speed) @@ -961,6 +999,12 @@ static int ftgmac100_mii_probe(struct ftgmac100 *priv) return PTR_ERR(phydev); } + /* Indicate that we support PAUSE frames (see comment in + * Documentation/networking/phy.txt) + */ + phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + phydev->advertising = phydev->supported; + return 0; } @@ -1076,6 +1120,48 @@ static int ftgmac100_set_ringparam(struct net_device *netdev, return 0; } +static void ftgmac100_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct ftgmac100 *priv = netdev_priv(netdev); + + pause->autoneg = priv->aneg_pause; + pause->tx_pause = priv->tx_pause; + pause->rx_pause = priv->rx_pause; +} + +static int ftgmac100_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct ftgmac100 *priv = netdev_priv(netdev); + struct phy_device *phydev = netdev->phydev; + + priv->aneg_pause = pause->autoneg; + priv->tx_pause = pause->tx_pause; + priv->rx_pause = pause->rx_pause; + + if (phydev) { + phydev->advertising &= ~ADVERTISED_Pause; + phydev->advertising &= ~ADVERTISED_Asym_Pause; + + if (pause->rx_pause) { + phydev->advertising |= ADVERTISED_Pause; + phydev->advertising |= ADVERTISED_Asym_Pause; + } + + if (pause->tx_pause) + phydev->advertising ^= ADVERTISED_Asym_Pause; + } + if (netif_running(netdev)) { + if (phydev && priv->aneg_pause) + phy_start_aneg(phydev); + else + ftgmac100_config_pause(priv); + } + + return 0; +} + static const struct ethtool_ops ftgmac100_ethtool_ops = { .get_drvinfo = ftgmac100_get_drvinfo, .get_link = ethtool_op_get_link, @@ -1084,6 +1170,8 @@ static const struct ethtool_ops ftgmac100_ethtool_ops = { .nway_reset = phy_ethtool_nway_reset, .get_ringparam = ftgmac100_get_ringparam, .set_ringparam = ftgmac100_set_ringparam, + .get_pauseparam = ftgmac100_get_pauseparam, + .set_pauseparam = ftgmac100_set_pauseparam, }; static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id) @@ -1215,6 +1303,7 @@ static int ftgmac100_init_all(struct ftgmac100 *priv, bool ignore_alloc_err) /* Reinit and restart HW */ ftgmac100_init_hw(priv); + ftgmac100_config_pause(priv); ftgmac100_start_hw(priv); /* Re-enable the device */ @@ -1544,6 +1633,11 @@ static int ftgmac100_probe(struct platform_device *pdev) netdev->irq = irq; + /* Enable pause */ + priv->tx_pause = true; + priv->rx_pause = true; + priv->aneg_pause = true; + /* MAC address from chip or random one */ ftgmac100_initial_mac(priv); diff --git a/drivers/net/ethernet/faraday/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h index 97912c4..0653d81 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.h +++ b/drivers/net/ethernet/faraday/ftgmac100.h @@ -199,6 +199,13 @@ #define FTGMAC100_PHYDATA_MIIRDATA(phydata) (((phydata) >> 16) & 0xffff) /* + * Flow control register + */ +#define FTGMAC100_FCR_FC_EN (1 << 0) +#define FTGMAC100_FCR_FCTHR_EN (1 << 2) +#define FTGMAC100_FCR_PAUSE_TIME(x) (((x) & 0xffff) << 16) + +/* * Transmit descriptor, aligned to 16 bytes */ struct ftgmac100_txdes {