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