cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pcs-xpcs.c (28696B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates.
      4 * Synopsys DesignWare XPCS helpers
      5 *
      6 * Author: Jose Abreu <Jose.Abreu@synopsys.com>
      7 */
      8
      9#include <linux/delay.h>
     10#include <linux/pcs/pcs-xpcs.h>
     11#include <linux/mdio.h>
     12#include <linux/phylink.h>
     13#include <linux/workqueue.h>
     14#include "pcs-xpcs.h"
     15
     16#define phylink_pcs_to_xpcs(pl_pcs) \
     17	container_of((pl_pcs), struct dw_xpcs, pcs)
     18
     19static const int xpcs_usxgmii_features[] = {
     20	ETHTOOL_LINK_MODE_Pause_BIT,
     21	ETHTOOL_LINK_MODE_Asym_Pause_BIT,
     22	ETHTOOL_LINK_MODE_Autoneg_BIT,
     23	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
     24	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
     25	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
     26	ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
     27	__ETHTOOL_LINK_MODE_MASK_NBITS,
     28};
     29
     30static const int xpcs_10gkr_features[] = {
     31	ETHTOOL_LINK_MODE_Pause_BIT,
     32	ETHTOOL_LINK_MODE_Asym_Pause_BIT,
     33	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
     34	__ETHTOOL_LINK_MODE_MASK_NBITS,
     35};
     36
     37static const int xpcs_xlgmii_features[] = {
     38	ETHTOOL_LINK_MODE_Pause_BIT,
     39	ETHTOOL_LINK_MODE_Asym_Pause_BIT,
     40	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
     41	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
     42	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
     43	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
     44	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
     45	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
     46	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
     47	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
     48	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
     49	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
     50	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
     51	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
     52	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
     53	ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
     54	ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
     55	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
     56	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
     57	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
     58	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
     59	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
     60	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
     61	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
     62	ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
     63	ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
     64	__ETHTOOL_LINK_MODE_MASK_NBITS,
     65};
     66
     67static const int xpcs_sgmii_features[] = {
     68	ETHTOOL_LINK_MODE_Pause_BIT,
     69	ETHTOOL_LINK_MODE_Asym_Pause_BIT,
     70	ETHTOOL_LINK_MODE_Autoneg_BIT,
     71	ETHTOOL_LINK_MODE_10baseT_Half_BIT,
     72	ETHTOOL_LINK_MODE_10baseT_Full_BIT,
     73	ETHTOOL_LINK_MODE_100baseT_Half_BIT,
     74	ETHTOOL_LINK_MODE_100baseT_Full_BIT,
     75	ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
     76	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
     77	__ETHTOOL_LINK_MODE_MASK_NBITS,
     78};
     79
     80static const int xpcs_2500basex_features[] = {
     81	ETHTOOL_LINK_MODE_Pause_BIT,
     82	ETHTOOL_LINK_MODE_Asym_Pause_BIT,
     83	ETHTOOL_LINK_MODE_Autoneg_BIT,
     84	ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
     85	ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
     86	__ETHTOOL_LINK_MODE_MASK_NBITS,
     87};
     88
     89static const phy_interface_t xpcs_usxgmii_interfaces[] = {
     90	PHY_INTERFACE_MODE_USXGMII,
     91};
     92
     93static const phy_interface_t xpcs_10gkr_interfaces[] = {
     94	PHY_INTERFACE_MODE_10GKR,
     95};
     96
     97static const phy_interface_t xpcs_xlgmii_interfaces[] = {
     98	PHY_INTERFACE_MODE_XLGMII,
     99};
    100
    101static const phy_interface_t xpcs_sgmii_interfaces[] = {
    102	PHY_INTERFACE_MODE_SGMII,
    103};
    104
    105static const phy_interface_t xpcs_2500basex_interfaces[] = {
    106	PHY_INTERFACE_MODE_2500BASEX,
    107	PHY_INTERFACE_MODE_MAX,
    108};
    109
    110enum {
    111	DW_XPCS_USXGMII,
    112	DW_XPCS_10GKR,
    113	DW_XPCS_XLGMII,
    114	DW_XPCS_SGMII,
    115	DW_XPCS_2500BASEX,
    116	DW_XPCS_INTERFACE_MAX,
    117};
    118
    119struct xpcs_compat {
    120	const int *supported;
    121	const phy_interface_t *interface;
    122	int num_interfaces;
    123	int an_mode;
    124	int (*pma_config)(struct dw_xpcs *xpcs);
    125};
    126
    127struct xpcs_id {
    128	u32 id;
    129	u32 mask;
    130	const struct xpcs_compat *compat;
    131};
    132
    133static const struct xpcs_compat *xpcs_find_compat(const struct xpcs_id *id,
    134						  phy_interface_t interface)
    135{
    136	int i, j;
    137
    138	for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) {
    139		const struct xpcs_compat *compat = &id->compat[i];
    140
    141		for (j = 0; j < compat->num_interfaces; j++)
    142			if (compat->interface[j] == interface)
    143				return compat;
    144	}
    145
    146	return NULL;
    147}
    148
    149int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
    150{
    151	const struct xpcs_compat *compat;
    152
    153	compat = xpcs_find_compat(xpcs->id, interface);
    154	if (!compat)
    155		return -ENODEV;
    156
    157	return compat->an_mode;
    158}
    159EXPORT_SYMBOL_GPL(xpcs_get_an_mode);
    160
    161static bool __xpcs_linkmode_supported(const struct xpcs_compat *compat,
    162				      enum ethtool_link_mode_bit_indices linkmode)
    163{
    164	int i;
    165
    166	for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
    167		if (compat->supported[i] == linkmode)
    168			return true;
    169
    170	return false;
    171}
    172
    173#define xpcs_linkmode_supported(compat, mode) \
    174	__xpcs_linkmode_supported(compat, ETHTOOL_LINK_MODE_ ## mode ## _BIT)
    175
    176int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)
    177{
    178	struct mii_bus *bus = xpcs->mdiodev->bus;
    179	int addr = xpcs->mdiodev->addr;
    180
    181	return mdiobus_c45_read(bus, addr, dev, reg);
    182}
    183
    184int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
    185{
    186	struct mii_bus *bus = xpcs->mdiodev->bus;
    187	int addr = xpcs->mdiodev->addr;
    188
    189	return mdiobus_c45_write(bus, addr, dev, reg, val);
    190}
    191
    192static int xpcs_read_vendor(struct dw_xpcs *xpcs, int dev, u32 reg)
    193{
    194	return xpcs_read(xpcs, dev, DW_VENDOR | reg);
    195}
    196
    197static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
    198			     u16 val)
    199{
    200	return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
    201}
    202
    203static int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
    204{
    205	return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
    206}
    207
    208static int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
    209{
    210	return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
    211}
    212
    213static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
    214{
    215	/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
    216	unsigned int retries = 12;
    217	int ret;
    218
    219	do {
    220		msleep(50);
    221		ret = xpcs_read(xpcs, dev, MDIO_CTRL1);
    222		if (ret < 0)
    223			return ret;
    224	} while (ret & MDIO_CTRL1_RESET && --retries);
    225
    226	return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0;
    227}
    228
    229static int xpcs_soft_reset(struct dw_xpcs *xpcs,
    230			   const struct xpcs_compat *compat)
    231{
    232	int ret, dev;
    233
    234	switch (compat->an_mode) {
    235	case DW_AN_C73:
    236		dev = MDIO_MMD_PCS;
    237		break;
    238	case DW_AN_C37_SGMII:
    239	case DW_2500BASEX:
    240		dev = MDIO_MMD_VEND2;
    241		break;
    242	default:
    243		return -1;
    244	}
    245
    246	ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET);
    247	if (ret < 0)
    248		return ret;
    249
    250	return xpcs_poll_reset(xpcs, dev);
    251}
    252
    253#define xpcs_warn(__xpcs, __state, __args...) \
    254({ \
    255	if ((__state)->link) \
    256		dev_warn(&(__xpcs)->mdiodev->dev, ##__args); \
    257})
    258
    259static int xpcs_read_fault_c73(struct dw_xpcs *xpcs,
    260			       struct phylink_link_state *state)
    261{
    262	int ret;
    263
    264	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
    265	if (ret < 0)
    266		return ret;
    267
    268	if (ret & MDIO_STAT1_FAULT) {
    269		xpcs_warn(xpcs, state, "Link fault condition detected!\n");
    270		return -EFAULT;
    271	}
    272
    273	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT2);
    274	if (ret < 0)
    275		return ret;
    276
    277	if (ret & MDIO_STAT2_RXFAULT)
    278		xpcs_warn(xpcs, state, "Receiver fault detected!\n");
    279	if (ret & MDIO_STAT2_TXFAULT)
    280		xpcs_warn(xpcs, state, "Transmitter fault detected!\n");
    281
    282	ret = xpcs_read_vendor(xpcs, MDIO_MMD_PCS, DW_VR_XS_PCS_DIG_STS);
    283	if (ret < 0)
    284		return ret;
    285
    286	if (ret & DW_RXFIFO_ERR) {
    287		xpcs_warn(xpcs, state, "FIFO fault condition detected!\n");
    288		return -EFAULT;
    289	}
    290
    291	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
    292	if (ret < 0)
    293		return ret;
    294
    295	if (!(ret & MDIO_PCS_10GBRT_STAT1_BLKLK))
    296		xpcs_warn(xpcs, state, "Link is not locked!\n");
    297
    298	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT2);
    299	if (ret < 0)
    300		return ret;
    301
    302	if (ret & MDIO_PCS_10GBRT_STAT2_ERR) {
    303		xpcs_warn(xpcs, state, "Link has errors!\n");
    304		return -EFAULT;
    305	}
    306
    307	return 0;
    308}
    309
    310static int xpcs_read_link_c73(struct dw_xpcs *xpcs, bool an)
    311{
    312	bool link = true;
    313	int ret;
    314
    315	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
    316	if (ret < 0)
    317		return ret;
    318
    319	if (!(ret & MDIO_STAT1_LSTATUS))
    320		link = false;
    321
    322	if (an) {
    323		ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
    324		if (ret < 0)
    325			return ret;
    326
    327		if (!(ret & MDIO_STAT1_LSTATUS))
    328			link = false;
    329	}
    330
    331	return link;
    332}
    333
    334static int xpcs_get_max_usxgmii_speed(const unsigned long *supported)
    335{
    336	int max = SPEED_UNKNOWN;
    337
    338	if (phylink_test(supported, 1000baseKX_Full))
    339		max = SPEED_1000;
    340	if (phylink_test(supported, 2500baseX_Full))
    341		max = SPEED_2500;
    342	if (phylink_test(supported, 10000baseKX4_Full))
    343		max = SPEED_10000;
    344	if (phylink_test(supported, 10000baseKR_Full))
    345		max = SPEED_10000;
    346
    347	return max;
    348}
    349
    350static void xpcs_config_usxgmii(struct dw_xpcs *xpcs, int speed)
    351{
    352	int ret, speed_sel;
    353
    354	switch (speed) {
    355	case SPEED_10:
    356		speed_sel = DW_USXGMII_10;
    357		break;
    358	case SPEED_100:
    359		speed_sel = DW_USXGMII_100;
    360		break;
    361	case SPEED_1000:
    362		speed_sel = DW_USXGMII_1000;
    363		break;
    364	case SPEED_2500:
    365		speed_sel = DW_USXGMII_2500;
    366		break;
    367	case SPEED_5000:
    368		speed_sel = DW_USXGMII_5000;
    369		break;
    370	case SPEED_10000:
    371		speed_sel = DW_USXGMII_10000;
    372		break;
    373	default:
    374		/* Nothing to do here */
    375		return;
    376	}
    377
    378	ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
    379	if (ret < 0)
    380		goto out;
    381
    382	ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_EN);
    383	if (ret < 0)
    384		goto out;
    385
    386	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
    387	if (ret < 0)
    388		goto out;
    389
    390	ret &= ~DW_USXGMII_SS_MASK;
    391	ret |= speed_sel | DW_USXGMII_FULL;
    392
    393	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
    394	if (ret < 0)
    395		goto out;
    396
    397	ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
    398	if (ret < 0)
    399		goto out;
    400
    401	ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST);
    402	if (ret < 0)
    403		goto out;
    404
    405	return;
    406
    407out:
    408	pr_err("%s: XPCS access returned %pe\n", __func__, ERR_PTR(ret));
    409}
    410
    411static int _xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
    412				 const struct xpcs_compat *compat)
    413{
    414	int ret, adv;
    415
    416	/* By default, in USXGMII mode XPCS operates at 10G baud and
    417	 * replicates data to achieve lower speeds. Hereby, in this
    418	 * default configuration we need to advertise all supported
    419	 * modes and not only the ones we want to use.
    420	 */
    421
    422	/* SR_AN_ADV3 */
    423	adv = 0;
    424	if (xpcs_linkmode_supported(compat, 2500baseX_Full))
    425		adv |= DW_C73_2500KX;
    426
    427	/* TODO: 5000baseKR */
    428
    429	ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV3, adv);
    430	if (ret < 0)
    431		return ret;
    432
    433	/* SR_AN_ADV2 */
    434	adv = 0;
    435	if (xpcs_linkmode_supported(compat, 1000baseKX_Full))
    436		adv |= DW_C73_1000KX;
    437	if (xpcs_linkmode_supported(compat, 10000baseKX4_Full))
    438		adv |= DW_C73_10000KX4;
    439	if (xpcs_linkmode_supported(compat, 10000baseKR_Full))
    440		adv |= DW_C73_10000KR;
    441
    442	ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV2, adv);
    443	if (ret < 0)
    444		return ret;
    445
    446	/* SR_AN_ADV1 */
    447	adv = DW_C73_AN_ADV_SF;
    448	if (xpcs_linkmode_supported(compat, Pause))
    449		adv |= DW_C73_PAUSE;
    450	if (xpcs_linkmode_supported(compat, Asym_Pause))
    451		adv |= DW_C73_ASYM_PAUSE;
    452
    453	return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv);
    454}
    455
    456static int xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
    457				const struct xpcs_compat *compat)
    458{
    459	int ret;
    460
    461	ret = _xpcs_config_aneg_c73(xpcs, compat);
    462	if (ret < 0)
    463		return ret;
    464
    465	ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_CTRL1);
    466	if (ret < 0)
    467		return ret;
    468
    469	ret |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART;
    470
    471	return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret);
    472}
    473
    474static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs,
    475			      struct phylink_link_state *state,
    476			      const struct xpcs_compat *compat)
    477{
    478	int ret;
    479
    480	ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
    481	if (ret < 0)
    482		return ret;
    483
    484	if (ret & MDIO_AN_STAT1_COMPLETE) {
    485		ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
    486		if (ret < 0)
    487			return ret;
    488
    489		/* Check if Aneg outcome is valid */
    490		if (!(ret & DW_C73_AN_ADV_SF)) {
    491			xpcs_config_aneg_c73(xpcs, compat);
    492			return 0;
    493		}
    494
    495		return 1;
    496	}
    497
    498	return 0;
    499}
    500
    501static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs,
    502			     struct phylink_link_state *state)
    503{
    504	int ret;
    505
    506	ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
    507	if (ret < 0)
    508		return ret;
    509
    510	if (!(ret & MDIO_AN_STAT1_LPABLE)) {
    511		phylink_clear(state->lp_advertising, Autoneg);
    512		return 0;
    513	}
    514
    515	phylink_set(state->lp_advertising, Autoneg);
    516
    517	/* Clause 73 outcome */
    518	ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL3);
    519	if (ret < 0)
    520		return ret;
    521
    522	if (ret & DW_C73_2500KX)
    523		phylink_set(state->lp_advertising, 2500baseX_Full);
    524
    525	ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL2);
    526	if (ret < 0)
    527		return ret;
    528
    529	if (ret & DW_C73_1000KX)
    530		phylink_set(state->lp_advertising, 1000baseKX_Full);
    531	if (ret & DW_C73_10000KX4)
    532		phylink_set(state->lp_advertising, 10000baseKX4_Full);
    533	if (ret & DW_C73_10000KR)
    534		phylink_set(state->lp_advertising, 10000baseKR_Full);
    535
    536	ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
    537	if (ret < 0)
    538		return ret;
    539
    540	if (ret & DW_C73_PAUSE)
    541		phylink_set(state->lp_advertising, Pause);
    542	if (ret & DW_C73_ASYM_PAUSE)
    543		phylink_set(state->lp_advertising, Asym_Pause);
    544
    545	linkmode_and(state->lp_advertising, state->lp_advertising,
    546		     state->advertising);
    547	return 0;
    548}
    549
    550static void xpcs_resolve_lpa_c73(struct dw_xpcs *xpcs,
    551				 struct phylink_link_state *state)
    552{
    553	int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising);
    554
    555	state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
    556	state->speed = max_speed;
    557	state->duplex = DUPLEX_FULL;
    558}
    559
    560static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs,
    561				     struct phylink_link_state *state)
    562{
    563	unsigned long *adv = state->advertising;
    564	int speed = SPEED_UNKNOWN;
    565	int bit;
    566
    567	for_each_set_bit(bit, adv, __ETHTOOL_LINK_MODE_MASK_NBITS) {
    568		int new_speed = SPEED_UNKNOWN;
    569
    570		switch (bit) {
    571		case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT:
    572		case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT:
    573		case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT:
    574			new_speed = SPEED_25000;
    575			break;
    576		case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT:
    577		case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT:
    578		case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT:
    579		case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT:
    580			new_speed = SPEED_40000;
    581			break;
    582		case ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT:
    583		case ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT:
    584		case ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT:
    585		case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT:
    586		case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT:
    587		case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT:
    588		case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT:
    589		case ETHTOOL_LINK_MODE_50000baseDR_Full_BIT:
    590			new_speed = SPEED_50000;
    591			break;
    592		case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT:
    593		case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT:
    594		case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT:
    595		case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT:
    596		case ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT:
    597		case ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT:
    598		case ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT:
    599		case ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT:
    600		case ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT:
    601			new_speed = SPEED_100000;
    602			break;
    603		default:
    604			continue;
    605		}
    606
    607		if (new_speed > speed)
    608			speed = new_speed;
    609	}
    610
    611	return speed;
    612}
    613
    614static void xpcs_resolve_pma(struct dw_xpcs *xpcs,
    615			     struct phylink_link_state *state)
    616{
    617	state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
    618	state->duplex = DUPLEX_FULL;
    619
    620	switch (state->interface) {
    621	case PHY_INTERFACE_MODE_10GKR:
    622		state->speed = SPEED_10000;
    623		break;
    624	case PHY_INTERFACE_MODE_XLGMII:
    625		state->speed = xpcs_get_max_xlgmii_speed(xpcs, state);
    626		break;
    627	default:
    628		state->speed = SPEED_UNKNOWN;
    629		break;
    630	}
    631}
    632
    633static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
    634			 const struct phylink_link_state *state)
    635{
    636	__ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported) = { 0, };
    637	const struct xpcs_compat *compat;
    638	struct dw_xpcs *xpcs;
    639	int i;
    640
    641	xpcs = phylink_pcs_to_xpcs(pcs);
    642	compat = xpcs_find_compat(xpcs->id, state->interface);
    643
    644	/* Populate the supported link modes for this PHY interface type.
    645	 * FIXME: what about the port modes and autoneg bit? This masks
    646	 * all those away.
    647	 */
    648	if (compat)
    649		for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
    650			set_bit(compat->supported[i], xpcs_supported);
    651
    652	linkmode_and(supported, supported, xpcs_supported);
    653
    654	return 0;
    655}
    656
    657void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
    658{
    659	int i, j;
    660
    661	for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) {
    662		const struct xpcs_compat *compat = &xpcs->id->compat[i];
    663
    664		for (j = 0; j < compat->num_interfaces; j++)
    665			if (compat->interface[j] < PHY_INTERFACE_MODE_MAX)
    666				__set_bit(compat->interface[j], interfaces);
    667	}
    668}
    669EXPORT_SYMBOL_GPL(xpcs_get_interfaces);
    670
    671int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable)
    672{
    673	int ret;
    674
    675	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0);
    676	if (ret < 0)
    677		return ret;
    678
    679	if (enable) {
    680	/* Enable EEE */
    681		ret = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
    682		      DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
    683		      DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
    684		      mult_fact_100ns << DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT;
    685	} else {
    686		ret &= ~(DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
    687		       DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
    688		       DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
    689		       DW_VR_MII_EEE_MULT_FACT_100NS);
    690	}
    691
    692	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, ret);
    693	if (ret < 0)
    694		return ret;
    695
    696	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1);
    697	if (ret < 0)
    698		return ret;
    699
    700	if (enable)
    701		ret |= DW_VR_MII_EEE_TRN_LPI;
    702	else
    703		ret &= ~DW_VR_MII_EEE_TRN_LPI;
    704
    705	return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, ret);
    706}
    707EXPORT_SYMBOL_GPL(xpcs_config_eee);
    708
    709static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode)
    710{
    711	int ret, mdio_ctrl;
    712
    713	/* For AN for C37 SGMII mode, the settings are :-
    714	 * 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case
    715	      it is already enabled)
    716	 * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
    717	 * 3) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
    718	 *    DW xPCS used with DW EQoS MAC is always MAC side SGMII.
    719	 * 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
    720	 *    speed/duplex mode change by HW after SGMII AN complete)
    721	 * 5) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 1b (Enable SGMII AN)
    722	 *
    723	 * Note: Since it is MAC side SGMII, there is no need to set
    724	 *	 SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from
    725	 *	 PHY about the link state change after C28 AN is completed
    726	 *	 between PHY and Link Partner. There is also no need to
    727	 *	 trigger AN restart for MAC-side SGMII.
    728	 */
    729	mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
    730	if (mdio_ctrl < 0)
    731		return mdio_ctrl;
    732
    733	if (mdio_ctrl & AN_CL37_EN) {
    734		ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
    735				 mdio_ctrl & ~AN_CL37_EN);
    736		if (ret < 0)
    737			return ret;
    738	}
    739
    740	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
    741	if (ret < 0)
    742		return ret;
    743
    744	ret &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK);
    745	ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
    746		DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
    747		DW_VR_MII_PCS_MODE_MASK);
    748	ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
    749		DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
    750		DW_VR_MII_TX_CONFIG_MASK);
    751	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
    752	if (ret < 0)
    753		return ret;
    754
    755	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
    756	if (ret < 0)
    757		return ret;
    758
    759	if (phylink_autoneg_inband(mode))
    760		ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
    761	else
    762		ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
    763
    764	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
    765	if (ret < 0)
    766		return ret;
    767
    768	if (phylink_autoneg_inband(mode))
    769		ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
    770				 mdio_ctrl | AN_CL37_EN);
    771
    772	return ret;
    773}
    774
    775static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
    776{
    777	int ret;
    778
    779	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
    780	if (ret < 0)
    781		return ret;
    782	ret |= DW_VR_MII_DIG_CTRL1_2G5_EN;
    783	ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
    784	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
    785	if (ret < 0)
    786		return ret;
    787
    788	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
    789	if (ret < 0)
    790		return ret;
    791	ret &= ~AN_CL37_EN;
    792	ret |= SGMII_SPEED_SS6;
    793	ret &= ~SGMII_SPEED_SS13;
    794	return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
    795}
    796
    797int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
    798		   unsigned int mode)
    799{
    800	const struct xpcs_compat *compat;
    801	int ret;
    802
    803	compat = xpcs_find_compat(xpcs->id, interface);
    804	if (!compat)
    805		return -ENODEV;
    806
    807	switch (compat->an_mode) {
    808	case DW_AN_C73:
    809		if (phylink_autoneg_inband(mode)) {
    810			ret = xpcs_config_aneg_c73(xpcs, compat);
    811			if (ret)
    812				return ret;
    813		}
    814		break;
    815	case DW_AN_C37_SGMII:
    816		ret = xpcs_config_aneg_c37_sgmii(xpcs, mode);
    817		if (ret)
    818			return ret;
    819		break;
    820	case DW_2500BASEX:
    821		ret = xpcs_config_2500basex(xpcs);
    822		if (ret)
    823			return ret;
    824		break;
    825	default:
    826		return -1;
    827	}
    828
    829	if (compat->pma_config) {
    830		ret = compat->pma_config(xpcs);
    831		if (ret)
    832			return ret;
    833	}
    834
    835	return 0;
    836}
    837EXPORT_SYMBOL_GPL(xpcs_do_config);
    838
    839static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode,
    840		       phy_interface_t interface,
    841		       const unsigned long *advertising,
    842		       bool permit_pause_to_mac)
    843{
    844	struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
    845
    846	return xpcs_do_config(xpcs, interface, mode);
    847}
    848
    849static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
    850			      struct phylink_link_state *state,
    851			      const struct xpcs_compat *compat)
    852{
    853	int ret;
    854
    855	/* Link needs to be read first ... */
    856	state->link = xpcs_read_link_c73(xpcs, state->an_enabled) > 0 ? 1 : 0;
    857
    858	/* ... and then we check the faults. */
    859	ret = xpcs_read_fault_c73(xpcs, state);
    860	if (ret) {
    861		ret = xpcs_soft_reset(xpcs, compat);
    862		if (ret)
    863			return ret;
    864
    865		state->link = 0;
    866
    867		return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND);
    868	}
    869
    870	if (state->an_enabled && xpcs_aneg_done_c73(xpcs, state, compat)) {
    871		state->an_complete = true;
    872		xpcs_read_lpa_c73(xpcs, state);
    873		xpcs_resolve_lpa_c73(xpcs, state);
    874	} else if (state->an_enabled) {
    875		state->link = 0;
    876	} else if (state->link) {
    877		xpcs_resolve_pma(xpcs, state);
    878	}
    879
    880	return 0;
    881}
    882
    883static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
    884				    struct phylink_link_state *state)
    885{
    886	int ret;
    887
    888	/* Reset link_state */
    889	state->link = false;
    890	state->speed = SPEED_UNKNOWN;
    891	state->duplex = DUPLEX_UNKNOWN;
    892	state->pause = 0;
    893
    894	/* For C37 SGMII mode, we check DW_VR_MII_AN_INTR_STS for link
    895	 * status, speed and duplex.
    896	 */
    897	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
    898	if (ret < 0)
    899		return false;
    900
    901	if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
    902		int speed_value;
    903
    904		state->link = true;
    905
    906		speed_value = (ret & DW_VR_MII_AN_STS_C37_ANSGM_SP) >>
    907			      DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT;
    908		if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000)
    909			state->speed = SPEED_1000;
    910		else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100)
    911			state->speed = SPEED_100;
    912		else
    913			state->speed = SPEED_10;
    914
    915		if (ret & DW_VR_MII_AN_STS_C37_ANSGM_FD)
    916			state->duplex = DUPLEX_FULL;
    917		else
    918			state->duplex = DUPLEX_HALF;
    919	}
    920
    921	return 0;
    922}
    923
    924static void xpcs_get_state(struct phylink_pcs *pcs,
    925			   struct phylink_link_state *state)
    926{
    927	struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
    928	const struct xpcs_compat *compat;
    929	int ret;
    930
    931	compat = xpcs_find_compat(xpcs->id, state->interface);
    932	if (!compat)
    933		return;
    934
    935	switch (compat->an_mode) {
    936	case DW_AN_C73:
    937		ret = xpcs_get_state_c73(xpcs, state, compat);
    938		if (ret) {
    939			pr_err("xpcs_get_state_c73 returned %pe\n",
    940			       ERR_PTR(ret));
    941			return;
    942		}
    943		break;
    944	case DW_AN_C37_SGMII:
    945		ret = xpcs_get_state_c37_sgmii(xpcs, state);
    946		if (ret) {
    947			pr_err("xpcs_get_state_c37_sgmii returned %pe\n",
    948			       ERR_PTR(ret));
    949		}
    950		break;
    951	default:
    952		return;
    953	}
    954}
    955
    956static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode,
    957			       int speed, int duplex)
    958{
    959	int val, ret;
    960
    961	if (phylink_autoneg_inband(mode))
    962		return;
    963
    964	switch (speed) {
    965	case SPEED_1000:
    966		val = BMCR_SPEED1000;
    967		break;
    968	case SPEED_100:
    969		val = BMCR_SPEED100;
    970		break;
    971	case SPEED_10:
    972		val = BMCR_SPEED10;
    973		break;
    974	default:
    975		return;
    976	}
    977
    978	if (duplex == DUPLEX_FULL)
    979		val |= BMCR_FULLDPLX;
    980
    981	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
    982	if (ret)
    983		pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
    984}
    985
    986void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
    987		  phy_interface_t interface, int speed, int duplex)
    988{
    989	struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
    990
    991	if (interface == PHY_INTERFACE_MODE_USXGMII)
    992		return xpcs_config_usxgmii(xpcs, speed);
    993	if (interface == PHY_INTERFACE_MODE_SGMII)
    994		return xpcs_link_up_sgmii(xpcs, mode, speed, duplex);
    995}
    996EXPORT_SYMBOL_GPL(xpcs_link_up);
    997
    998static u32 xpcs_get_id(struct dw_xpcs *xpcs)
    999{
   1000	int ret;
   1001	u32 id;
   1002
   1003	/* First, search C73 PCS using PCS MMD */
   1004	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
   1005	if (ret < 0)
   1006		return 0xffffffff;
   1007
   1008	id = ret << 16;
   1009
   1010	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID2);
   1011	if (ret < 0)
   1012		return 0xffffffff;
   1013
   1014	/* If Device IDs are not all zeros or all ones,
   1015	 * we found C73 AN-type device
   1016	 */
   1017	if ((id | ret) && (id | ret) != 0xffffffff)
   1018		return id | ret;
   1019
   1020	/* Next, search C37 PCS using Vendor-Specific MII MMD */
   1021	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1);
   1022	if (ret < 0)
   1023		return 0xffffffff;
   1024
   1025	id = ret << 16;
   1026
   1027	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2);
   1028	if (ret < 0)
   1029		return 0xffffffff;
   1030
   1031	/* If Device IDs are not all zeros, we found C37 AN-type device */
   1032	if (id | ret)
   1033		return id | ret;
   1034
   1035	return 0xffffffff;
   1036}
   1037
   1038static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
   1039	[DW_XPCS_USXGMII] = {
   1040		.supported = xpcs_usxgmii_features,
   1041		.interface = xpcs_usxgmii_interfaces,
   1042		.num_interfaces = ARRAY_SIZE(xpcs_usxgmii_interfaces),
   1043		.an_mode = DW_AN_C73,
   1044	},
   1045	[DW_XPCS_10GKR] = {
   1046		.supported = xpcs_10gkr_features,
   1047		.interface = xpcs_10gkr_interfaces,
   1048		.num_interfaces = ARRAY_SIZE(xpcs_10gkr_interfaces),
   1049		.an_mode = DW_AN_C73,
   1050	},
   1051	[DW_XPCS_XLGMII] = {
   1052		.supported = xpcs_xlgmii_features,
   1053		.interface = xpcs_xlgmii_interfaces,
   1054		.num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces),
   1055		.an_mode = DW_AN_C73,
   1056	},
   1057	[DW_XPCS_SGMII] = {
   1058		.supported = xpcs_sgmii_features,
   1059		.interface = xpcs_sgmii_interfaces,
   1060		.num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
   1061		.an_mode = DW_AN_C37_SGMII,
   1062	},
   1063	[DW_XPCS_2500BASEX] = {
   1064		.supported = xpcs_2500basex_features,
   1065		.interface = xpcs_2500basex_interfaces,
   1066		.num_interfaces = ARRAY_SIZE(xpcs_2500basex_features),
   1067		.an_mode = DW_2500BASEX,
   1068	},
   1069};
   1070
   1071static const struct xpcs_compat nxp_sja1105_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
   1072	[DW_XPCS_SGMII] = {
   1073		.supported = xpcs_sgmii_features,
   1074		.interface = xpcs_sgmii_interfaces,
   1075		.num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
   1076		.an_mode = DW_AN_C37_SGMII,
   1077		.pma_config = nxp_sja1105_sgmii_pma_config,
   1078	},
   1079};
   1080
   1081static const struct xpcs_compat nxp_sja1110_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
   1082	[DW_XPCS_SGMII] = {
   1083		.supported = xpcs_sgmii_features,
   1084		.interface = xpcs_sgmii_interfaces,
   1085		.num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
   1086		.an_mode = DW_AN_C37_SGMII,
   1087		.pma_config = nxp_sja1110_sgmii_pma_config,
   1088	},
   1089	[DW_XPCS_2500BASEX] = {
   1090		.supported = xpcs_2500basex_features,
   1091		.interface = xpcs_2500basex_interfaces,
   1092		.num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces),
   1093		.an_mode = DW_2500BASEX,
   1094		.pma_config = nxp_sja1110_2500basex_pma_config,
   1095	},
   1096};
   1097
   1098static const struct xpcs_id xpcs_id_list[] = {
   1099	{
   1100		.id = SYNOPSYS_XPCS_ID,
   1101		.mask = SYNOPSYS_XPCS_MASK,
   1102		.compat = synopsys_xpcs_compat,
   1103	}, {
   1104		.id = NXP_SJA1105_XPCS_ID,
   1105		.mask = SYNOPSYS_XPCS_MASK,
   1106		.compat = nxp_sja1105_xpcs_compat,
   1107	}, {
   1108		.id = NXP_SJA1110_XPCS_ID,
   1109		.mask = SYNOPSYS_XPCS_MASK,
   1110		.compat = nxp_sja1110_xpcs_compat,
   1111	},
   1112};
   1113
   1114static const struct phylink_pcs_ops xpcs_phylink_ops = {
   1115	.pcs_validate = xpcs_validate,
   1116	.pcs_config = xpcs_config,
   1117	.pcs_get_state = xpcs_get_state,
   1118	.pcs_link_up = xpcs_link_up,
   1119};
   1120
   1121struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
   1122			    phy_interface_t interface)
   1123{
   1124	struct dw_xpcs *xpcs;
   1125	u32 xpcs_id;
   1126	int i, ret;
   1127
   1128	xpcs = kzalloc(sizeof(*xpcs), GFP_KERNEL);
   1129	if (!xpcs)
   1130		return ERR_PTR(-ENOMEM);
   1131
   1132	xpcs->mdiodev = mdiodev;
   1133
   1134	xpcs_id = xpcs_get_id(xpcs);
   1135
   1136	for (i = 0; i < ARRAY_SIZE(xpcs_id_list); i++) {
   1137		const struct xpcs_id *entry = &xpcs_id_list[i];
   1138		const struct xpcs_compat *compat;
   1139
   1140		if ((xpcs_id & entry->mask) != entry->id)
   1141			continue;
   1142
   1143		xpcs->id = entry;
   1144
   1145		compat = xpcs_find_compat(entry, interface);
   1146		if (!compat) {
   1147			ret = -ENODEV;
   1148			goto out;
   1149		}
   1150
   1151		xpcs->pcs.ops = &xpcs_phylink_ops;
   1152		xpcs->pcs.poll = true;
   1153
   1154		ret = xpcs_soft_reset(xpcs, compat);
   1155		if (ret)
   1156			goto out;
   1157
   1158		return xpcs;
   1159	}
   1160
   1161	ret = -ENODEV;
   1162
   1163out:
   1164	kfree(xpcs);
   1165
   1166	return ERR_PTR(ret);
   1167}
   1168EXPORT_SYMBOL_GPL(xpcs_create);
   1169
   1170void xpcs_destroy(struct dw_xpcs *xpcs)
   1171{
   1172	kfree(xpcs);
   1173}
   1174EXPORT_SYMBOL_GPL(xpcs_destroy);
   1175
   1176MODULE_LICENSE("GPL v2");