All of lore.kernel.org
 help / color / mirror / Atom feed
From: Voon Weifeng <weifeng.voon@intel.com>
To: "David S. Miller" <davem@davemloft.net>,
	Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	Jose Abreu <joabreu@synopsys.com>,
	Giuseppe Cavallaro <peppe.cavallaro@st.com>,
	Andrew Lunn <andrew@lunn.ch>,
	Florian Fainelli <f.fainelli@gmail.com>,
	Alexandre Torgue <alexandre.torgue@st.com>,
	biao huang <biao.huang@mediatek.com>,
	Ong Boon Leong <boon.leong.ong@intel.com>,
	Kweh Hock Leong <hock.leong.kweh@intel.com>,
	Voon Weifeng <weifeng.voon@intel.com>
Subject: [PATCH net-next v4 3/5] net: stmmac: add xpcs function hooks into main driver and ethtool
Date: Thu, 30 May 2019 00:58:25 +0800	[thread overview]
Message-ID: <1559149107-14631-4-git-send-email-weifeng.voon@intel.com> (raw)
In-Reply-To: <1559149107-14631-1-git-send-email-weifeng.voon@intel.com>

From: Ong Boon Leong <boon.leong.ong@intel.com>

With xPCS functions now ready, we add them into the main driver and
ethtool logics. To differentiate from EQoS MAC PCS and DWC Ethernet
xPCS, we introduce 'has_xpcs' in platform data as a mean to indicate
whether GBE controller includes xPCS or not.

To support platform-specific C37 AN PCS mode selection for MII MMD,
we introduce 'pcs_mode' in platform data.

The basic framework for xPCS interrupt handling is implemented too.

Reviewed-by: Chuah Kim Tatt <kim.tatt.chuah@intel.com>
Reviewed-by: Voon Weifeng <weifeng.voon@intel.com>
Reviewed-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
Reviewed-by: Baoli Zhang <baoli.zhang@intel.com>
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
Signed-off-by: Voon Weifeng <weifeng.voon@intel.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h       |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 +++++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 152 ++++++++++++++++-----
 include/linux/stmmac.h                             |   2 +
 4 files changed, 158 insertions(+), 48 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index a16ada8b8507..999311236521 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -36,6 +36,7 @@ struct stmmac_resources {
 	const char *mac;
 	int wol_irq;
 	int lpi_irq;
+	int xpcs_irq;
 	int irq;
 };
 
@@ -168,6 +169,7 @@ struct stmmac_priv {
 	int clk_csr;
 	struct timer_list eee_ctrl_timer;
 	int lpi_irq;
+	int xpcs_irq;
 	int eee_enabled;
 	int eee_active;
 	int tx_lpi_timer;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index cec51ba34296..be6edbe3d658 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -28,6 +28,7 @@
 
 #include "stmmac.h"
 #include "dwmac_dma.h"
+#include "dwxpcs.h"
 
 #define REG_SPACE_SIZE	0x1060
 #define MAC100_ETHTOOL_NAME	"st_mac100"
@@ -277,7 +278,8 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
 	struct phy_device *phy = dev->phydev;
 
 	if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-	    priv->hw->pcs & STMMAC_PCS_SGMII) {
+	    priv->hw->pcs & STMMAC_PCS_SGMII ||
+	    priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
 		struct rgmii_adv adv;
 		u32 supported, advertising, lp_advertising;
 
@@ -294,6 +296,11 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
 		if (stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv))
 			return -EOPNOTSUPP;	/* should never happen indeed */
 
+		/* Get ADV & LPA is only application for 1000BASE-X C37.
+		 * For MAC side SGMII AN, get ADV & LPA from PHY.
+		 */
+		stmmac_xpcs_get_adv_lp(priv, dev, &adv, priv->plat->pcs_mode);
+
 		/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
 
 		ethtool_convert_link_mode_to_legacy_u32(
@@ -376,22 +383,23 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
 	int rc;
 
 	if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-	    priv->hw->pcs & STMMAC_PCS_SGMII) {
-		u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
-
+	    priv->hw->pcs & STMMAC_PCS_SGMII ||
+	    priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
 		/* Only support ANE */
 		if (cmd->base.autoneg != AUTONEG_ENABLE)
 			return -EINVAL;
 
-		mask &= (ADVERTISED_1000baseT_Half |
-			ADVERTISED_1000baseT_Full |
-			ADVERTISED_100baseT_Half |
-			ADVERTISED_100baseT_Full |
-			ADVERTISED_10baseT_Half |
-			ADVERTISED_10baseT_Full);
-
 		mutex_lock(&priv->lock);
 		stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0);
+
+		/* For 1000BASE-X C37 AN, it is always 1000Mbps. And, we only
+		 * support FD which is set by default in SR_MII_AN_ADV
+		 * during XPCS init. So, we don't need to set FD again.
+		 * For SGMII C37 AN, we let user to change link settings
+		 * through PHY since it is MAC side SGMII.
+		 */
+		stmmac_xpcs_ctrl_ane(priv, dev, 1, 0);
+
 		mutex_unlock(&priv->lock);
 
 		return 0;
@@ -457,6 +465,16 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
 		pause->autoneg = 1;
 		if (!adv_lp.pause)
 			return;
+	} else if (priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX &&
+		   !stmmac_xpcs_get_adv_lp(priv, netdev, &adv_lp,
+					   priv->plat->pcs_mode)) {
+		/* DW xPCS 1000BASE-X C37 AN mode only because for MAC side
+		 * SGMII C37 AN, xPCS AN ADV is not set. See more comment in
+		 * dw_xpcs_init()
+		 */
+		pause->autoneg = 1;
+		if (!adv_lp.pause)
+			return;
 	} else {
 		if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
 				       netdev->phydev->supported) ||
@@ -488,6 +506,16 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
 		pause->autoneg = 1;
 		if (!adv_lp.pause)
 			return -EOPNOTSUPP;
+	} else if (priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX &&
+		   !stmmac_xpcs_get_adv_lp(priv, netdev, &adv_lp,
+					   priv->plat->pcs_mode)) {
+		/* DW xPCS 1000BASE-X C37 AN mode only because for MAC side
+		 * SGMII C37 AN, xPCS AN ADV is not set. See more comment in
+		 * dw_xpcs_init()
+		 */
+		pause->autoneg = 1;
+		if (!adv_lp.pause)
+			return -EOPNOTSUPP;
 	} else {
 		if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
 				       phy->supported) ||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index a87ec70b19f1..1c27503e983c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -112,6 +112,7 @@
 MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode");
 
 static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+static irqreturn_t xpcs_interrupt(int irq, void *dev_id);
 
 #ifdef CONFIG_DEBUG_FS
 static int stmmac_init_fs(struct net_device *dev);
@@ -848,6 +849,55 @@ static void stmmac_mac_flow_ctrl(struct stmmac_priv *priv, u32 duplex)
 			priv->pause, tx_cnt);
 }
 
+static bool mac_adjust_link(struct stmmac_priv *priv,
+			    int *speed, int *duplex)
+{
+	bool new_state = false;
+
+	u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
+
+	/* Now we make sure that we can be in full duplex mode.
+	 * If not, we operate in half-duplex mode.
+	 */
+	if (*duplex != priv->oldduplex) {
+		new_state = true;
+		if (!*duplex)
+			ctrl &= ~priv->hw->link.duplex;
+		else
+			ctrl |= priv->hw->link.duplex;
+		priv->oldduplex = *duplex;
+	}
+
+	if (*speed != priv->speed) {
+		new_state = true;
+		ctrl &= ~priv->hw->link.speed_mask;
+		switch (*speed) {
+		case SPEED_1000:
+			ctrl |= priv->hw->link.speed1000;
+			break;
+		case SPEED_100:
+			ctrl |= priv->hw->link.speed100;
+			break;
+		case SPEED_10:
+			ctrl |= priv->hw->link.speed10;
+			break;
+		default:
+			netif_warn(priv, link, priv->dev,
+				   "broken speed: %d\n", *speed);
+			*speed = SPEED_UNKNOWN;
+			break;
+		}
+		if (*speed != SPEED_UNKNOWN)
+			stmmac_hw_fix_mac_speed(priv);
+
+		priv->speed = *speed;
+	}
+
+	writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
+
+	return new_state;
+}
+
 /**
  * stmmac_adjust_link - adjusts the link parameters
  * @dev: net device structure
@@ -869,47 +919,12 @@ static void stmmac_adjust_link(struct net_device *dev)
 	mutex_lock(&priv->lock);
 
 	if (phydev->link) {
-		u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
-
-		/* Now we make sure that we can be in full duplex mode.
-		 * If not, we operate in half-duplex mode. */
-		if (phydev->duplex != priv->oldduplex) {
-			new_state = true;
-			if (!phydev->duplex)
-				ctrl &= ~priv->hw->link.duplex;
-			else
-				ctrl |= priv->hw->link.duplex;
-			priv->oldduplex = phydev->duplex;
-		}
 		/* Flow Control operation */
 		if (phydev->pause)
 			stmmac_mac_flow_ctrl(priv, phydev->duplex);
 
-		if (phydev->speed != priv->speed) {
-			new_state = true;
-			ctrl &= ~priv->hw->link.speed_mask;
-			switch (phydev->speed) {
-			case SPEED_1000:
-				ctrl |= priv->hw->link.speed1000;
-				break;
-			case SPEED_100:
-				ctrl |= priv->hw->link.speed100;
-				break;
-			case SPEED_10:
-				ctrl |= priv->hw->link.speed10;
-				break;
-			default:
-				netif_warn(priv, link, priv->dev,
-					   "broken speed: %d\n", phydev->speed);
-				phydev->speed = SPEED_UNKNOWN;
-				break;
-			}
-			if (phydev->speed != SPEED_UNKNOWN)
-				stmmac_hw_fix_mac_speed(priv);
-			priv->speed = phydev->speed;
-		}
-
-		writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
+		new_state = mac_adjust_link(priv, &phydev->speed,
+					    &phydev->duplex);
 
 		if (!priv->oldlink) {
 			new_state = true;
@@ -2541,6 +2556,9 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
 	/* Initialize MTL*/
 	stmmac_mtl_configuration(priv);
 
+	/* Initialize the xPCS PHY */
+	stmmac_xpcs_init(priv, dev, priv->plat->pcs_mode);
+
 	/* Initialize Safety Features */
 	stmmac_safety_feat_configuration(priv);
 
@@ -2582,6 +2600,8 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
 	if (priv->hw->pcs)
 		stmmac_pcs_ctrl_ane(priv, priv->hw, 1, priv->hw->ps, 0);
 
+	stmmac_xpcs_ctrl_ane(priv, dev, 1, 0);
+
 	/* set TX and RX rings length */
 	stmmac_set_rings_length(priv);
 
@@ -2697,11 +2717,27 @@ static int stmmac_open(struct net_device *dev)
 		}
 	}
 
+	/* xPCS IRQ line */
+	if (priv->xpcs_irq > 0) {
+		ret = request_irq(priv->xpcs_irq, xpcs_interrupt, IRQF_SHARED,
+				  dev->name, dev);
+		if (unlikely(ret < 0)) {
+			netdev_err(priv->dev,
+				   "%s: ERROR: allocating the xPCS IRQ %d (%d)\n",
+				   __func__, priv->xpcs_irq, ret);
+			goto xpcsirq_error;
+		}
+	}
+
 	stmmac_enable_all_queues(priv);
 	stmmac_start_all_queues(priv);
 
 	return 0;
 
+xpcsirq_error:
+	if (priv->lpi_irq > 0)
+		free_irq(priv->lpi_irq, dev);
+
 lpiirq_error:
 	if (priv->wol_irq != dev->irq)
 		free_irq(priv->wol_irq, dev);
@@ -3775,6 +3811,47 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/**
+ *  xPCS_interrupt - xPCS ISR
+ *  @irq: interrupt number.
+ *  @dev_id: to pass the net device pointer.
+ *  Description: this is the xPCS interrupt service routine.
+ */
+static irqreturn_t xpcs_interrupt(int irq, void *dev_id)
+{
+	struct net_device *ndev = (struct net_device *)dev_id;
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	irqreturn_t ret = IRQ_NONE;
+
+	if (unlikely(!ndev)) {
+		netdev_err(priv->dev, "%s: invalid dev pointer\n",
+			   __func__);
+		return ret;
+	}
+
+	/* To handle xPCS interrupts */
+	ret = stmmac_xpcs_irq_status(priv, ndev, &priv->xstats,
+				     priv->plat->pcs_mode);
+
+	if (ret == IRQ_HANDLED) {
+		/* Keep the MAC's speed & duplex consistent with DW xPCS
+		 * because AN in DW xPCS does not update DW EQoS MAC
+		 * directly.
+		 */
+		int speed = (int)priv->xstats.pcs_speed;
+		int duplex = (int)priv->xstats.pcs_speed;
+
+		mac_adjust_link(priv, &speed, &duplex);
+
+		if (priv->xstats.pcs_link)
+			netif_carrier_on(ndev);
+		else
+			netif_carrier_off(ndev);
+	}
+
+	return ret;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /* Polling receive - used by NETCONSOLE and other diagnostic tools
  * to allow network I/O with interrupts disabled.
@@ -4264,6 +4341,7 @@ int stmmac_dvr_probe(struct device *device,
 	priv->dev->irq = res->irq;
 	priv->wol_irq = res->wol_irq;
 	priv->lpi_irq = res->lpi_irq;
+	priv->xpcs_irq = res->xpcs_irq;
 
 	if (!IS_ERR_OR_NULL(res->mac))
 		memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index b00e7951a66d..c6778abd41c5 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -189,6 +189,8 @@ struct plat_stmmacenet_data {
 	struct reset_control *stmmac_rst;
 	struct stmmac_axi *axi;
 	int has_gmac4;
+	bool has_xpcs;
+	int pcs_mode;
 	bool has_sun8i;
 	bool tso_en;
 	int mac_port_sel_speed;
-- 
1.9.1


  parent reply	other threads:[~2019-05-29  8:58 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-29 16:58 [PATCH net-next v4 0/5] net: stmmac: enable EHL SGMI Voon Weifeng
2019-05-29 16:58 ` [PATCH net-next v4 1/5] net: stmmac: enable clause 45 mdio support Voon Weifeng
2019-05-29 10:16   ` Jose Abreu
2019-05-29 17:39     ` Voon, Weifeng
2019-05-29 23:06       ` Andrew Lunn
2019-05-29 16:58 ` [PATCH net-next v4 2/5] net: stmmac: introducing support for DWC xPCS logics Voon Weifeng
2019-05-29 10:19   ` Jose Abreu
2019-05-29 16:58 ` Voon Weifeng [this message]
2019-05-29 10:23   ` [PATCH net-next v4 3/5] net: stmmac: add xpcs function hooks into main driver and ethtool Jose Abreu
2019-05-29 16:58 ` [PATCH net-next v4 4/5] net: stmmac: add xPCS functions for device with DWMACv5.1 Voon Weifeng
2019-05-29 10:25   ` Jose Abreu
2019-05-29 16:58 ` [PATCH net-next v4 5/5] net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID Voon Weifeng
2019-05-29 10:28   ` Jose Abreu
2019-05-29 18:00     ` Voon, Weifeng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1559149107-14631-4-git-send-email-weifeng.voon@intel.com \
    --to=weifeng.voon@intel.com \
    --cc=alexandre.torgue@st.com \
    --cc=andrew@lunn.ch \
    --cc=biao.huang@mediatek.com \
    --cc=boon.leong.ong@intel.com \
    --cc=davem@davemloft.net \
    --cc=f.fainelli@gmail.com \
    --cc=hock.leong.kweh@intel.com \
    --cc=joabreu@synopsys.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mcoquelin.stm32@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=peppe.cavallaro@st.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.