diff options
| -rw-r--r-- | Documentation/networking/device_drivers/stmicro/stmmac.rst | 7 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/common.h | 13 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 99 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwxlgmac2.h | 22 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/hwif.c | 45 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/hwif.h | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 58 | ||||
| -rw-r--r-- | drivers/net/phy/mdio-xpcs.c | 98 | 
8 files changed, 340 insertions, 3 deletions
| diff --git a/Documentation/networking/device_drivers/stmicro/stmmac.rst b/Documentation/networking/device_drivers/stmicro/stmmac.rst index c34bab3d2df0..5d46e5036129 100644 --- a/Documentation/networking/device_drivers/stmicro/stmmac.rst +++ b/Documentation/networking/device_drivers/stmicro/stmmac.rst @@ -32,7 +32,8 @@ is also supported.  DesignWare(R) Cores Ethernet MAC 10/100/1000 Universal version 3.70a  (and older) and DesignWare(R) Cores Ethernet Quality-of-Service version 4.0  (and upper) have been used for developing this driver as well as -DesignWare(R) Cores XGMAC - 10G Ethernet MAC. +DesignWare(R) Cores XGMAC - 10G Ethernet MAC and DesignWare(R) Cores +Enterprise MAC - 100G Ethernet MAC.  This driver supports both the platform bus and PCI. @@ -48,6 +49,8 @@ Cores Ethernet Controllers and corresponding minimum and maximum versions:  +-------------------------------+--------------+--------------+--------------+  | XGMAC - 10G Ethernet MAC      | 2.10a        | N/A          | XGMAC2+      |  +-------------------------------+--------------+--------------+--------------+ +| XLGMAC - 100G Ethernet MAC    | 2.00a        | N/A          | XLGMAC2+     | ++-------------------------------+--------------+--------------+--------------+  For questions related to hardware requirements, refer to the documentation  supplied with your Ethernet adapter. All hardware requirements listed apply @@ -57,7 +60,7 @@ Feature List  ============  The following features are available in this driver: - - GMII/MII/RGMII/SGMII/RMII/XGMII Interface + - GMII/MII/RGMII/SGMII/RMII/XGMII/XLGMII Interface   - Half-Duplex / Full-Duplex Operation   - Energy Efficient Ethernet (EEE)   - IEEE 802.3x PAUSE Packets (Flow Control) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 9bdbf589d93f..386663208c23 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -34,6 +34,11 @@  #define DWMAC_CORE_5_00		0x50  #define DWMAC_CORE_5_10		0x51  #define DWXGMAC_CORE_2_10	0x21 +#define DWXLGMAC_CORE_2_00	0x20 + +/* Device ID */ +#define DWXGMAC_ID		0x76 +#define DWXLGMAC_ID		0x27  #define STMMAC_CHAN0	0	/* Always supported and default for all chips */ @@ -426,6 +431,12 @@ struct mac_link {  		u32 speed5000;  		u32 speed10000;  	} xgmii; +	struct { +		u32 speed25000; +		u32 speed40000; +		u32 speed50000; +		u32 speed100000; +	} xlgmii;  };  struct mii_regs { @@ -459,6 +470,7 @@ struct mac_device_info {  	unsigned int pcs;  	unsigned int pmt;  	unsigned int ps; +	unsigned int xlgmac;  };  struct stmmac_rx_routing { @@ -470,6 +482,7 @@ int dwmac100_setup(struct stmmac_priv *priv);  int dwmac1000_setup(struct stmmac_priv *priv);  int dwmac4_setup(struct stmmac_priv *priv);  int dwxgmac2_setup(struct stmmac_priv *priv); +int dwxlgmac2_setup(struct stmmac_priv *priv);  void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],  			 unsigned int high, unsigned int low); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 67b754a56288..0e4575f7bedb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -9,6 +9,7 @@  #include <linux/iopoll.h>  #include "stmmac.h"  #include "stmmac_ptp.h" +#include "dwxlgmac2.h"  #include "dwxgmac2.h"  static void dwxgmac2_core_init(struct mac_device_info *hw, @@ -1485,6 +1486,67 @@ const struct stmmac_ops dwxgmac210_ops = {  	.fpe_configure = dwxgmac3_fpe_configure,  }; +static void dwxlgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode, +				      u32 queue) +{ +	void __iomem *ioaddr = hw->pcsr; +	u32 value; + +	value = readl(ioaddr + XLGMAC_RXQ_ENABLE_CTRL0) & ~XGMAC_RXQEN(queue); +	if (mode == MTL_QUEUE_AVB) +		value |= 0x1 << XGMAC_RXQEN_SHIFT(queue); +	else if (mode == MTL_QUEUE_DCB) +		value |= 0x2 << XGMAC_RXQEN_SHIFT(queue); +	writel(value, ioaddr + XLGMAC_RXQ_ENABLE_CTRL0); +} + +const struct stmmac_ops dwxlgmac2_ops = { +	.core_init = dwxgmac2_core_init, +	.set_mac = dwxgmac2_set_mac, +	.rx_ipc = dwxgmac2_rx_ipc, +	.rx_queue_enable = dwxlgmac2_rx_queue_enable, +	.rx_queue_prio = dwxgmac2_rx_queue_prio, +	.tx_queue_prio = dwxgmac2_tx_queue_prio, +	.rx_queue_routing = NULL, +	.prog_mtl_rx_algorithms = dwxgmac2_prog_mtl_rx_algorithms, +	.prog_mtl_tx_algorithms = dwxgmac2_prog_mtl_tx_algorithms, +	.set_mtl_tx_queue_weight = dwxgmac2_set_mtl_tx_queue_weight, +	.map_mtl_to_dma = dwxgmac2_map_mtl_to_dma, +	.config_cbs = dwxgmac2_config_cbs, +	.dump_regs = dwxgmac2_dump_regs, +	.host_irq_status = dwxgmac2_host_irq_status, +	.host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, +	.flow_ctrl = dwxgmac2_flow_ctrl, +	.pmt = dwxgmac2_pmt, +	.set_umac_addr = dwxgmac2_set_umac_addr, +	.get_umac_addr = dwxgmac2_get_umac_addr, +	.set_eee_mode = dwxgmac2_set_eee_mode, +	.reset_eee_mode = dwxgmac2_reset_eee_mode, +	.set_eee_timer = dwxgmac2_set_eee_timer, +	.set_eee_pls = dwxgmac2_set_eee_pls, +	.pcs_ctrl_ane = NULL, +	.pcs_rane = NULL, +	.pcs_get_adv_lp = NULL, +	.debug = NULL, +	.set_filter = dwxgmac2_set_filter, +	.safety_feat_config = dwxgmac3_safety_feat_config, +	.safety_feat_irq_status = dwxgmac3_safety_feat_irq_status, +	.safety_feat_dump = dwxgmac3_safety_feat_dump, +	.set_mac_loopback = dwxgmac2_set_mac_loopback, +	.rss_configure = dwxgmac2_rss_configure, +	.update_vlan_hash = dwxgmac2_update_vlan_hash, +	.rxp_config = dwxgmac3_rxp_config, +	.get_mac_tx_timestamp = dwxgmac2_get_mac_tx_timestamp, +	.flex_pps_config = dwxgmac2_flex_pps_config, +	.sarc_configure = dwxgmac2_sarc_configure, +	.enable_vlan = dwxgmac2_enable_vlan, +	.config_l3_filter = dwxgmac2_config_l3_filter, +	.config_l4_filter = dwxgmac2_config_l4_filter, +	.set_arp_offload = dwxgmac2_set_arp_offload, +	.est_configure = dwxgmac3_est_configure, +	.fpe_configure = dwxgmac3_fpe_configure, +}; +  int dwxgmac2_setup(struct stmmac_priv *priv)  {  	struct mac_device_info *mac = priv->hw; @@ -1521,3 +1583,40 @@ int dwxgmac2_setup(struct stmmac_priv *priv)  	return 0;  } + +int dwxlgmac2_setup(struct stmmac_priv *priv) +{ +	struct mac_device_info *mac = priv->hw; + +	dev_info(priv->device, "\tXLGMAC\n"); + +	priv->dev->priv_flags |= IFF_UNICAST_FLT; +	mac->pcsr = priv->ioaddr; +	mac->multicast_filter_bins = priv->plat->multicast_filter_bins; +	mac->unicast_filter_entries = priv->plat->unicast_filter_entries; +	mac->mcast_bits_log2 = 0; + +	if (mac->multicast_filter_bins) +		mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); + +	mac->link.duplex = 0; +	mac->link.speed1000 = XLGMAC_CONFIG_SS_1000; +	mac->link.speed2500 = XLGMAC_CONFIG_SS_2500; +	mac->link.xgmii.speed10000 = XLGMAC_CONFIG_SS_10G; +	mac->link.xlgmii.speed25000 = XLGMAC_CONFIG_SS_25G; +	mac->link.xlgmii.speed40000 = XLGMAC_CONFIG_SS_40G; +	mac->link.xlgmii.speed50000 = XLGMAC_CONFIG_SS_50G; +	mac->link.xlgmii.speed100000 = XLGMAC_CONFIG_SS_100G; +	mac->link.speed_mask = XLGMAC_CONFIG_SS; + +	mac->mii.addr = XGMAC_MDIO_ADDR; +	mac->mii.data = XGMAC_MDIO_DATA; +	mac->mii.addr_shift = 16; +	mac->mii.addr_mask = GENMASK(20, 16); +	mac->mii.reg_shift = 0; +	mac->mii.reg_mask = GENMASK(15, 0); +	mac->mii.clk_csr_shift = 19; +	mac->mii.clk_csr_mask = GENMASK(21, 19); + +	return 0; +} diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxlgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxlgmac2.h new file mode 100644 index 000000000000..726090d49221 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwxlgmac2.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates. + * Synopsys DesignWare XLGMAC definitions. + */ + +#ifndef __STMMAC_DWXLGMAC2_H__ +#define __STMMAC_DWXLGMAC2_H__ + +/* MAC Registers */ +#define XLGMAC_CONFIG_SS		GENMASK(30, 28) +#define XLGMAC_CONFIG_SS_SHIFT		28 +#define XLGMAC_CONFIG_SS_40G		(0x0 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_25G		(0x1 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_50G		(0x2 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_100G		(0x3 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_10G		(0x4 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_2500		(0x6 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_CONFIG_SS_1000		(0x7 << XLGMAC_CONFIG_SS_SHIFT) +#define XLGMAC_RXQ_ENABLE_CTRL0		0x00000140 + +#endif /* __STMMAC_DWXLGMAC2_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 3af2e5015245..bb7114f970f8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -23,6 +23,18 @@ static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg)  	return reg & GENMASK(7, 0);  } +static u32 stmmac_get_dev_id(struct stmmac_priv *priv, u32 id_reg) +{ +	u32 reg = readl(priv->ioaddr + id_reg); + +	if (!reg) { +		dev_info(priv->device, "Version ID not available\n"); +		return 0x0; +	} + +	return (reg & GENMASK(15, 8)) >> 8; +} +  static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv)  {  	struct mac_device_info *mac = priv->hw; @@ -69,11 +81,18 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)  	return 0;  } +static int stmmac_dwxlgmac_quirks(struct stmmac_priv *priv) +{ +	priv->hw->xlgmac = true; +	return 0; +} +  static const struct stmmac_hwif_entry {  	bool gmac;  	bool gmac4;  	bool xgmac;  	u32 min_id; +	u32 dev_id;  	const struct stmmac_regs_off regs;  	const void *desc;  	const void *dma; @@ -199,6 +218,7 @@ static const struct stmmac_hwif_entry {  		.gmac4 = false,  		.xgmac = true,  		.min_id = DWXGMAC_CORE_2_10, +		.dev_id = DWXGMAC_ID,  		.regs = {  			.ptp_off = PTP_XGMAC_OFFSET,  			.mmc_off = MMC_XGMAC_OFFSET, @@ -212,6 +232,25 @@ static const struct stmmac_hwif_entry {  		.mmc = &dwxgmac_mmc_ops,  		.setup = dwxgmac2_setup,  		.quirks = NULL, +	}, { +		.gmac = false, +		.gmac4 = false, +		.xgmac = true, +		.min_id = DWXLGMAC_CORE_2_00, +		.dev_id = DWXLGMAC_ID, +		.regs = { +			.ptp_off = PTP_XGMAC_OFFSET, +			.mmc_off = MMC_XGMAC_OFFSET, +		}, +		.desc = &dwxgmac210_desc_ops, +		.dma = &dwxgmac210_dma_ops, +		.mac = &dwxlgmac2_ops, +		.hwtimestamp = &stmmac_ptp, +		.mode = NULL, +		.tc = &dwmac510_tc_ops, +		.mmc = &dwxgmac_mmc_ops, +		.setup = dwxlgmac2_setup, +		.quirks = stmmac_dwxlgmac_quirks,  	},  }; @@ -223,13 +262,15 @@ int stmmac_hwif_init(struct stmmac_priv *priv)  	const struct stmmac_hwif_entry *entry;  	struct mac_device_info *mac;  	bool needs_setup = true; +	u32 id, dev_id = 0;  	int i, ret; -	u32 id;  	if (needs_gmac) {  		id = stmmac_get_id(priv, GMAC_VERSION);  	} else if (needs_gmac4 || needs_xgmac) {  		id = stmmac_get_id(priv, GMAC4_VERSION); +		if (needs_xgmac) +			dev_id = stmmac_get_dev_id(priv, GMAC4_VERSION);  	} else {  		id = 0;  	} @@ -267,6 +308,8 @@ int stmmac_hwif_init(struct stmmac_priv *priv)  		/* Use synopsys_id var because some setups can override this */  		if (priv->synopsys_id < entry->min_id)  			continue; +		if (needs_xgmac && (dev_id ^ entry->dev_id)) +			continue;  		/* Only use generic HW helpers if needed */  		mac->desc = mac->desc ? : entry->desc; diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index c71dd99c8abf..fc350149ba34 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -605,6 +605,7 @@ extern const struct stmmac_dma_ops dwmac410_dma_ops;  extern const struct stmmac_ops dwmac510_ops;  extern const struct stmmac_tc_ops dwmac510_tc_ops;  extern const struct stmmac_ops dwxgmac210_ops; +extern const struct stmmac_ops dwxlgmac2_ops;  extern const struct stmmac_dma_ops dwxgmac210_dma_ops;  extern const struct stmmac_desc_ops dwxgmac210_desc_ops;  extern const struct stmmac_mmc_ops dwmac_mmc_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f26699d9a050..0e8c80f23557 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -849,6 +849,38 @@ static void stmmac_validate(struct phylink_config *config,  			phylink_set(mac_supported, 10000baseKX4_Full);  			phylink_set(mac_supported, 10000baseKR_Full);  		} +		if (!max_speed || (max_speed >= 25000)) { +			phylink_set(mac_supported, 25000baseCR_Full); +			phylink_set(mac_supported, 25000baseKR_Full); +			phylink_set(mac_supported, 25000baseSR_Full); +		} +		if (!max_speed || (max_speed >= 40000)) { +			phylink_set(mac_supported, 40000baseKR4_Full); +			phylink_set(mac_supported, 40000baseCR4_Full); +			phylink_set(mac_supported, 40000baseSR4_Full); +			phylink_set(mac_supported, 40000baseLR4_Full); +		} +		if (!max_speed || (max_speed >= 50000)) { +			phylink_set(mac_supported, 50000baseCR2_Full); +			phylink_set(mac_supported, 50000baseKR2_Full); +			phylink_set(mac_supported, 50000baseSR2_Full); +			phylink_set(mac_supported, 50000baseKR_Full); +			phylink_set(mac_supported, 50000baseSR_Full); +			phylink_set(mac_supported, 50000baseCR_Full); +			phylink_set(mac_supported, 50000baseLR_ER_FR_Full); +			phylink_set(mac_supported, 50000baseDR_Full); +		} +		if (!max_speed || (max_speed >= 100000)) { +			phylink_set(mac_supported, 100000baseKR4_Full); +			phylink_set(mac_supported, 100000baseSR4_Full); +			phylink_set(mac_supported, 100000baseCR4_Full); +			phylink_set(mac_supported, 100000baseLR4_ER4_Full); +			phylink_set(mac_supported, 100000baseKR2_Full); +			phylink_set(mac_supported, 100000baseSR2_Full); +			phylink_set(mac_supported, 100000baseCR2_Full); +			phylink_set(mac_supported, 100000baseLR2_ER2_FR2_Full); +			phylink_set(mac_supported, 100000baseDR2_Full); +		}  	}  	/* Half-Duplex can only work with single queue */ @@ -929,6 +961,32 @@ static void stmmac_mac_link_up(struct phylink_config *config,  		default:  			return;  		} +	} else if (interface == PHY_INTERFACE_MODE_XLGMII) { +		switch (speed) { +		case SPEED_100000: +			ctrl |= priv->hw->link.xlgmii.speed100000; +			break; +		case SPEED_50000: +			ctrl |= priv->hw->link.xlgmii.speed50000; +			break; +		case SPEED_40000: +			ctrl |= priv->hw->link.xlgmii.speed40000; +			break; +		case SPEED_25000: +			ctrl |= priv->hw->link.xlgmii.speed25000; +			break; +		case SPEED_10000: +			ctrl |= priv->hw->link.xgmii.speed10000; +			break; +		case SPEED_2500: +			ctrl |= priv->hw->link.speed2500; +			break; +		case SPEED_1000: +			ctrl |= priv->hw->link.speed1000; +			break; +		default: +			return; +		}  	} else {  		switch (speed) {  		case SPEED_2500: diff --git a/drivers/net/phy/mdio-xpcs.c b/drivers/net/phy/mdio-xpcs.c index 973f588146f7..2f4cdf807160 100644 --- a/drivers/net/phy/mdio-xpcs.c +++ b/drivers/net/phy/mdio-xpcs.c @@ -14,6 +14,7 @@  #define SYNOPSYS_XPCS_USXGMII_ID	0x7996ced0  #define SYNOPSYS_XPCS_10GKR_ID		0x7996ced0 +#define SYNOPSYS_XPCS_XLGMII_ID		0x7996ced0  #define SYNOPSYS_XPCS_MASK		0xffffffff  /* Vendor regs access */ @@ -74,6 +75,36 @@ static const int xpcs_10gkr_features[] = {  	__ETHTOOL_LINK_MODE_MASK_NBITS,  }; +static const int xpcs_xlgmii_features[] = { +	ETHTOOL_LINK_MODE_Pause_BIT, +	ETHTOOL_LINK_MODE_Asym_Pause_BIT, +	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, +	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, +	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, +	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, +	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, +	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, +	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, +	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, +	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, +	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, +	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, +	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, +	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, +	ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, +	ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, +	ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, +	__ETHTOOL_LINK_MODE_MASK_NBITS, +}; +  static const phy_interface_t xpcs_usxgmii_interfaces[] = {  	PHY_INTERFACE_MODE_USXGMII,  	PHY_INTERFACE_MODE_MAX, @@ -84,6 +115,11 @@ static const phy_interface_t xpcs_10gkr_interfaces[] = {  	PHY_INTERFACE_MODE_MAX,  }; +static const phy_interface_t xpcs_xlgmii_interfaces[] = { +	PHY_INTERFACE_MODE_XLGMII, +	PHY_INTERFACE_MODE_MAX, +}; +  static struct xpcs_id {  	u32 id;  	u32 mask; @@ -100,6 +136,11 @@ static struct xpcs_id {  		.mask = SYNOPSYS_XPCS_MASK,  		.supported = xpcs_10gkr_features,  		.interface = xpcs_10gkr_interfaces, +	}, { +		.id = SYNOPSYS_XPCS_XLGMII_ID, +		.mask = SYNOPSYS_XPCS_MASK, +		.supported = xpcs_xlgmii_features, +		.interface = xpcs_xlgmii_interfaces,  	},  }; @@ -458,6 +499,60 @@ static void xpcs_resolve_lpa(struct mdio_xpcs_args *xpcs,  	state->duplex = DUPLEX_FULL;  } +static int xpcs_get_max_xlgmii_speed(struct mdio_xpcs_args *xpcs, +				     struct phylink_link_state *state) +{ +	unsigned long *adv = state->advertising; +	int speed = SPEED_UNKNOWN; +	int bit; + +	for_each_set_bit(bit, adv, __ETHTOOL_LINK_MODE_MASK_NBITS) { +		int new_speed = SPEED_UNKNOWN; + +		switch (bit) { +		case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT: +		case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT: +		case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT: +			new_speed = SPEED_25000; +			break; +		case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT: +		case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT: +		case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT: +		case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT: +			new_speed = SPEED_40000; +			break; +		case ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT: +		case ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT: +		case ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT: +		case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT: +		case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT: +		case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT: +		case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT: +		case ETHTOOL_LINK_MODE_50000baseDR_Full_BIT: +			new_speed = SPEED_50000; +			break; +		case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT: +		case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT: +		case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT: +		case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT: +		case ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT: +		case ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT: +		case ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT: +		case ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT: +		case ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT: +			new_speed = SPEED_100000; +			break; +		default: +			continue; +		} + +		if (new_speed > speed) +			speed = new_speed; +	} + +	return speed; +} +  static void xpcs_resolve_pma(struct mdio_xpcs_args *xpcs,  			     struct phylink_link_state *state)  { @@ -468,6 +563,9 @@ static void xpcs_resolve_pma(struct mdio_xpcs_args *xpcs,  	case PHY_INTERFACE_MODE_10GKR:  		state->speed = SPEED_10000;  		break; +	case PHY_INTERFACE_MODE_XLGMII: +		state->speed = xpcs_get_max_xlgmii_speed(xpcs, state); +		break;  	default:  		state->speed = SPEED_UNKNOWN;  		break; | 
