Commit e442cfc7 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-Add-support-for-Synopsys-DesignWare-XPCS'



Jose Abreu says:

====================
net: Add support for Synopsys DesignWare XPCS

This adds support for Synopsys DesignWare XPCS in net subsystem and
integrates it into stmmac.

At 1/8, we start by removing the limitation of stmmac selftests that needed
a PHY to pass all the tests.

Then at 2/8 we use some helpers in stmmac so that some code can be
simplified.

At 3/8, we fallback to dev_fwnode() so that PCI based setups wich may
not have CONFIG_OF can still use FW node.

At 4/8, we adapt stmmac to the new PHYLINK changes as suggested by Russell
King.

We proceed by doing changes in PHYLINK in order to support XPCS: At 5/8 we
add some missing speeds that USXGMII supports and at 6/8 we check if
Autoneg is supported after initial parameters are validated.

Support for XPCS is finally introduced at 7/8, along with the usage of it
in stmmac driver at 8/8.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6c9ee306 f213bbe8
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -16117,6 +16117,13 @@ L: netdev@vger.kernel.org
S:	Supported
F:	drivers/net/ethernet/synopsys/
SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER
M:	Jose Abreu <Jose.Abreu@synopsys.com>
L:	netdev@vger.kernel.org
S:	Supported
F:	drivers/net/phy/mdio-xpcs.c
F:	include/linux/mdio-xpcs.h
SYNOPSYS DESIGNWARE I2C DRIVER
M:	Jarkko Nikula <jarkko.nikula@linux.intel.com>
R:	Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ config STMMAC_ETH
	tristate "STMicroelectronics Multi-Gigabit Ethernet driver"
	depends on HAS_IOMEM && HAS_DMA
	select MII
	select MDIO_XPCS
	select PAGE_POOL
	select PHYLINK
	select CRC32
+3 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/netdevice.h>
#include <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/mdio-xpcs.h>
#include <linux/module.h>
#if IS_ENABLED(CONFIG_VLAN_8021Q)
#define STMMAC_VLAN_TAG_USED
@@ -446,6 +447,8 @@ struct mac_device_info {
	const struct stmmac_hwtimestamp *ptp;
	const struct stmmac_tc_ops *tc;
	const struct stmmac_mmc_ops *mmc;
	const struct mdio_xpcs_ops *xpcs;
	struct mdio_xpcs_args xpcs_args;
	struct mii_regs mii;	/* MII register Addresses */
	struct mac_link link;
	void __iomem *pcsr;     /* vpointer to device CSRs */
+12 −0
Original line number Diff line number Diff line
@@ -577,6 +577,18 @@ struct stmmac_mmc_ops {
#define stmmac_mmc_read(__priv, __args...) \
	stmmac_do_void_callback(__priv, mmc, read, __args)

/* XPCS callbacks */
#define stmmac_xpcs_validate(__priv, __args...) \
	stmmac_do_callback(__priv, xpcs, validate, __args)
#define stmmac_xpcs_config(__priv, __args...) \
	stmmac_do_callback(__priv, xpcs, config, __args)
#define stmmac_xpcs_get_state(__priv, __args...) \
	stmmac_do_callback(__priv, xpcs, get_state, __args)
#define stmmac_xpcs_link_up(__priv, __args...) \
	stmmac_do_callback(__priv, xpcs, link_up, __args)
#define stmmac_xpcs_probe(__priv, __args...) \
	stmmac_do_callback(__priv, xpcs, probe, __args)

struct stmmac_regs_off {
	u32 ptp_off;
	u32 mmc_off;
+54 −42
Original line number Diff line number Diff line
@@ -858,33 +858,65 @@ static void stmmac_validate(struct phylink_config *config,
		phylink_set(mask, 1000baseT_Half);
	}

	bitmap_and(supported, supported, mac_supported,
		   __ETHTOOL_LINK_MODE_MASK_NBITS);
	bitmap_andnot(supported, supported, mask,
		      __ETHTOOL_LINK_MODE_MASK_NBITS);
	bitmap_and(state->advertising, state->advertising, mac_supported,
		   __ETHTOOL_LINK_MODE_MASK_NBITS);
	bitmap_andnot(state->advertising, state->advertising, mask,
		      __ETHTOOL_LINK_MODE_MASK_NBITS);
	linkmode_and(supported, supported, mac_supported);
	linkmode_andnot(supported, supported, mask);

	linkmode_and(state->advertising, state->advertising, mac_supported);
	linkmode_andnot(state->advertising, state->advertising, mask);

	/* If PCS is supported, check which modes it supports. */
	stmmac_xpcs_validate(priv, &priv->hw->xpcs_args, supported, state);
}

static void stmmac_mac_pcs_get_state(struct phylink_config *config,
				     struct phylink_link_state *state)
{
	struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));

	state->link = 0;
	stmmac_xpcs_get_state(priv, &priv->hw->xpcs_args, state);
}

static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
			      const struct phylink_link_state *state)
{
	struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));

	stmmac_xpcs_config(priv, &priv->hw->xpcs_args, state);
}

static void stmmac_mac_an_restart(struct phylink_config *config)
{
	/* Not Supported */
}

static void stmmac_mac_link_down(struct phylink_config *config,
				 unsigned int mode, phy_interface_t interface)
{
	struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));

	stmmac_mac_set(priv, priv->ioaddr, false);
	priv->eee_active = false;
	stmmac_eee_init(priv);
	stmmac_set_eee_pls(priv, priv->hw, false);
}

static void stmmac_mac_link_up(struct phylink_config *config,
			       struct phy_device *phy,
			       unsigned int mode, phy_interface_t interface,
			       int speed, int duplex,
			       bool tx_pause, bool rx_pause)
{
	struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
	u32 ctrl;

	stmmac_xpcs_link_up(priv, &priv->hw->xpcs_args, speed, interface);

	ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
	ctrl &= ~priv->hw->link.speed_mask;

	if (state->interface == PHY_INTERFACE_MODE_USXGMII) {
		switch (state->speed) {
	if (interface == PHY_INTERFACE_MODE_USXGMII) {
		switch (speed) {
		case SPEED_10000:
			ctrl |= priv->hw->link.xgmii.speed10000;
			break;
@@ -898,7 +930,7 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
			return;
		}
	} else {
		switch (state->speed) {
		switch (speed) {
		case SPEED_2500:
			ctrl |= priv->hw->link.speed2500;
			break;
@@ -916,46 +948,21 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
		}
	}

	priv->speed = state->speed;
	priv->speed = speed;

	if (priv->plat->fix_mac_speed)
		priv->plat->fix_mac_speed(priv->plat->bsp_priv, state->speed);
		priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed);

	if (!state->duplex)
	if (!duplex)
		ctrl &= ~priv->hw->link.duplex;
	else
		ctrl |= priv->hw->link.duplex;

	/* Flow Control operation */
	if (state->pause)
		stmmac_mac_flow_ctrl(priv, state->duplex);
	if (tx_pause && rx_pause)
		stmmac_mac_flow_ctrl(priv, duplex);

	writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
}

static void stmmac_mac_an_restart(struct phylink_config *config)
{
	/* Not Supported */
}

static void stmmac_mac_link_down(struct phylink_config *config,
				 unsigned int mode, phy_interface_t interface)
{
	struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));

	stmmac_mac_set(priv, priv->ioaddr, false);
	priv->eee_active = false;
	stmmac_eee_init(priv);
	stmmac_set_eee_pls(priv, priv->hw, false);
}

static void stmmac_mac_link_up(struct phylink_config *config,
			       struct phy_device *phy,
			       unsigned int mode, phy_interface_t interface,
			       int speed, int duplex,
			       bool tx_pause, bool rx_pause)
{
	struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));

	stmmac_mac_set(priv, priv->ioaddr, true);
	if (phy && priv->dma_cap.eee) {
@@ -1045,6 +1052,10 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)

	priv->phylink_config.dev = &priv->dev->dev;
	priv->phylink_config.type = PHYLINK_NETDEV;
	priv->phylink_config.pcs_poll = true;

	if (!fwnode)
		fwnode = dev_fwnode(priv->device);

	phylink = phylink_create(&priv->phylink_config, fwnode,
				 mode, &stmmac_phylink_mac_ops);
@@ -2689,7 +2700,8 @@ static int stmmac_open(struct net_device *dev)
	int ret;

	if (priv->hw->pcs != STMMAC_PCS_TBI &&
	    priv->hw->pcs != STMMAC_PCS_RTBI) {
	    priv->hw->pcs != STMMAC_PCS_RTBI &&
	    priv->hw->xpcs == NULL) {
		ret = stmmac_init_phy(dev);
		if (ret) {
			netdev_err(priv->dev,
Loading