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
  15#define SYNOPSYS_XPCS_USXGMII_ID        0x7996ced0
  16#define SYNOPSYS_XPCS_10GKR_ID          0x7996ced0
  17#define SYNOPSYS_XPCS_XLGMII_ID         0x7996ced0
  18#define SYNOPSYS_XPCS_MASK              0xffffffff
  19
  20/* Vendor regs access */
  21#define DW_VENDOR                       BIT(15)
  22
  23/* VR_XS_PCS */
  24#define DW_USXGMII_RST                  BIT(10)
  25#define DW_USXGMII_EN                   BIT(9)
  26#define DW_VR_XS_PCS_DIG_STS            0x0010
  27#define DW_RXFIFO_ERR                   GENMASK(6, 5)
  28
  29/* SR_MII */
  30#define DW_USXGMII_FULL                 BIT(8)
  31#define DW_USXGMII_SS_MASK              (BIT(13) | BIT(6) | BIT(5))
  32#define DW_USXGMII_10000                (BIT(13) | BIT(6))
  33#define DW_USXGMII_5000                 (BIT(13) | BIT(5))
  34#define DW_USXGMII_2500                 (BIT(5))
  35#define DW_USXGMII_1000                 (BIT(6))
  36#define DW_USXGMII_100                  (BIT(13))
  37#define DW_USXGMII_10                   (0)
  38
  39/* SR_AN */
  40#define DW_SR_AN_ADV1                   0x10
  41#define DW_SR_AN_ADV2                   0x11
  42#define DW_SR_AN_ADV3                   0x12
  43#define DW_SR_AN_LP_ABL1                0x13
  44#define DW_SR_AN_LP_ABL2                0x14
  45#define DW_SR_AN_LP_ABL3                0x15
  46
  47/* Clause 73 Defines */
  48/* AN_LP_ABL1 */
  49#define DW_C73_PAUSE                    BIT(10)
  50#define DW_C73_ASYM_PAUSE               BIT(11)
  51#define DW_C73_AN_ADV_SF                0x1
  52/* AN_LP_ABL2 */
  53#define DW_C73_1000KX                   BIT(5)
  54#define DW_C73_10000KX4                 BIT(6)
  55#define DW_C73_10000KR                  BIT(7)
  56/* AN_LP_ABL3 */
  57#define DW_C73_2500KX                   BIT(0)
  58#define DW_C73_5000KR                   BIT(1)
  59
  60static const int xpcs_usxgmii_features[] = {
  61        ETHTOOL_LINK_MODE_Pause_BIT,
  62        ETHTOOL_LINK_MODE_Asym_Pause_BIT,
  63        ETHTOOL_LINK_MODE_Autoneg_BIT,
  64        ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
  65        ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
  66        ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
  67        ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
  68        __ETHTOOL_LINK_MODE_MASK_NBITS,
  69};
  70
  71static const int xpcs_10gkr_features[] = {
  72        ETHTOOL_LINK_MODE_Pause_BIT,
  73        ETHTOOL_LINK_MODE_Asym_Pause_BIT,
  74        ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
  75        __ETHTOOL_LINK_MODE_MASK_NBITS,
  76};
  77
  78static const int xpcs_xlgmii_features[] = {
  79        ETHTOOL_LINK_MODE_Pause_BIT,
  80        ETHTOOL_LINK_MODE_Asym_Pause_BIT,
  81        ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
  82        ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
  83        ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
  84        ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
  85        ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
  86        ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
  87        ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
  88        ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
  89        ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
  90        ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
  91        ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
  92        ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
  93        ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
  94        ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
  95        ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
  96        ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
  97        ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
  98        ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
  99        ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
 100        ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
 101        ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
 102        ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
 103        ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
 104        ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
 105        __ETHTOOL_LINK_MODE_MASK_NBITS,
 106};
 107
 108static const phy_interface_t xpcs_usxgmii_interfaces[] = {
 109        PHY_INTERFACE_MODE_USXGMII,
 110        PHY_INTERFACE_MODE_MAX,
 111};
 112
 113static const phy_interface_t xpcs_10gkr_interfaces[] = {
 114        PHY_INTERFACE_MODE_10GKR,
 115        PHY_INTERFACE_MODE_MAX,
 116};
 117
 118static const phy_interface_t xpcs_xlgmii_interfaces[] = {
 119        PHY_INTERFACE_MODE_XLGMII,
 120        PHY_INTERFACE_MODE_MAX,
 121};
 122
 123static struct xpcs_id {
 124        u32 id;
 125        u32 mask;
 126        const int *supported;
 127        const phy_interface_t *interface;
 128} xpcs_id_list[] = {
 129        {
 130                .id = SYNOPSYS_XPCS_USXGMII_ID,
 131                .mask = SYNOPSYS_XPCS_MASK,
 132                .supported = xpcs_usxgmii_features,
 133                .interface = xpcs_usxgmii_interfaces,
 134        }, {
 135                .id = SYNOPSYS_XPCS_10GKR_ID,
 136                .mask = SYNOPSYS_XPCS_MASK,
 137                .supported = xpcs_10gkr_features,
 138                .interface = xpcs_10gkr_interfaces,
 139        }, {
 140                .id = SYNOPSYS_XPCS_XLGMII_ID,
 141                .mask = SYNOPSYS_XPCS_MASK,
 142                .supported = xpcs_xlgmii_features,
 143                .interface = xpcs_xlgmii_interfaces,
 144        },
 145};
 146
 147static int xpcs_read(struct mdio_xpcs_args *xpcs, int dev, u32 reg)
 148{
 149        u32 reg_addr = MII_ADDR_C45 | dev << 16 | reg;
 150
 151        return mdiobus_read(xpcs->bus, xpcs->addr, reg_addr);
 152}
 153
 154static int xpcs_write(struct mdio_xpcs_args *xpcs, int dev, u32 reg, u16 val)
 155{
 156        u32 reg_addr = MII_ADDR_C45 | dev << 16 | reg;
 157
 158        return mdiobus_write(xpcs->bus, xpcs->addr, reg_addr, val);
 159}
 160
 161static int xpcs_read_vendor(struct mdio_xpcs_args *xpcs, int dev, u32 reg)
 162{
 163        return xpcs_read(xpcs, dev, DW_VENDOR | reg);
 164}
 165
 166static int xpcs_write_vendor(struct mdio_xpcs_args *xpcs, int dev, int reg,
 167                             u16 val)
 168{
 169        return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
 170}
 171
 172static int xpcs_read_vpcs(struct mdio_xpcs_args *xpcs, int reg)
 173{
 174        return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
 175}
 176
 177static int xpcs_write_vpcs(struct mdio_xpcs_args *xpcs, int reg, u16 val)
 178{
 179        return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
 180}
 181
 182static int xpcs_poll_reset(struct mdio_xpcs_args *xpcs, int dev)
 183{
 184        /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
 185        unsigned int retries = 12;
 186        int ret;
 187
 188        do {
 189                msleep(50);
 190                ret = xpcs_read(xpcs, dev, MDIO_CTRL1);
 191                if (ret < 0)
 192                        return ret;
 193        } while (ret & MDIO_CTRL1_RESET && --retries);
 194
 195        return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0;
 196}
 197
 198static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs, int dev)
 199{
 200        int ret;
 201
 202        ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET);
 203        if (ret < 0)
 204                return ret;
 205
 206        return xpcs_poll_reset(xpcs, dev);
 207}
 208
 209#define xpcs_warn(__xpcs, __state, __args...) \
 210({ \
 211        if ((__state)->link) \
 212                dev_warn(&(__xpcs)->bus->dev, ##__args); \
 213})
 214
 215static int xpcs_read_fault(struct mdio_xpcs_args *xpcs,
 216                           struct phylink_link_state *state)
 217{
 218        int ret;
 219
 220        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
 221        if (ret < 0)
 222                return ret;
 223
 224        if (ret & MDIO_STAT1_FAULT) {
 225                xpcs_warn(xpcs, state, "Link fault condition detected!\n");
 226                return -EFAULT;
 227        }
 228
 229        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT2);
 230        if (ret < 0)
 231                return ret;
 232
 233        if (ret & MDIO_STAT2_RXFAULT)
 234                xpcs_warn(xpcs, state, "Receiver fault detected!\n");
 235        if (ret & MDIO_STAT2_TXFAULT)
 236                xpcs_warn(xpcs, state, "Transmitter fault detected!\n");
 237
 238        ret = xpcs_read_vendor(xpcs, MDIO_MMD_PCS, DW_VR_XS_PCS_DIG_STS);
 239        if (ret < 0)
 240                return ret;
 241
 242        if (ret & DW_RXFIFO_ERR) {
 243                xpcs_warn(xpcs, state, "FIFO fault condition detected!\n");
 244                return -EFAULT;
 245        }
 246
 247        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
 248        if (ret < 0)
 249                return ret;
 250
 251        if (!(ret & MDIO_PCS_10GBRT_STAT1_BLKLK))
 252                xpcs_warn(xpcs, state, "Link is not locked!\n");
 253
 254        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT2);
 255        if (ret < 0)
 256                return ret;
 257
 258        if (ret & MDIO_PCS_10GBRT_STAT2_ERR) {
 259                xpcs_warn(xpcs, state, "Link has errors!\n");
 260                return -EFAULT;
 261        }
 262
 263        return 0;
 264}
 265
 266static int xpcs_read_link(struct mdio_xpcs_args *xpcs, bool an)
 267{
 268        bool link = true;
 269        int ret;
 270
 271        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
 272        if (ret < 0)
 273                return ret;
 274
 275        if (!(ret & MDIO_STAT1_LSTATUS))
 276                link = false;
 277
 278        if (an) {
 279                ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
 280                if (ret < 0)
 281                        return ret;
 282
 283                if (!(ret & MDIO_STAT1_LSTATUS))
 284                        link = false;
 285        }
 286
 287        return link;
 288}
 289
 290static int xpcs_get_max_usxgmii_speed(const unsigned long *supported)
 291{
 292        int max = SPEED_UNKNOWN;
 293
 294        if (phylink_test(supported, 1000baseKX_Full))
 295                max = SPEED_1000;
 296        if (phylink_test(supported, 2500baseX_Full))
 297                max = SPEED_2500;
 298        if (phylink_test(supported, 10000baseKX4_Full))
 299                max = SPEED_10000;
 300        if (phylink_test(supported, 10000baseKR_Full))
 301                max = SPEED_10000;
 302
 303        return max;
 304}
 305
 306static int xpcs_config_usxgmii(struct mdio_xpcs_args *xpcs, int speed)
 307{
 308        int ret, speed_sel;
 309
 310        switch (speed) {
 311        case SPEED_10:
 312                speed_sel = DW_USXGMII_10;
 313                break;
 314        case SPEED_100:
 315                speed_sel = DW_USXGMII_100;
 316                break;
 317        case SPEED_1000:
 318                speed_sel = DW_USXGMII_1000;
 319                break;
 320        case SPEED_2500:
 321                speed_sel = DW_USXGMII_2500;
 322                break;
 323        case SPEED_5000:
 324                speed_sel = DW_USXGMII_5000;
 325                break;
 326        case SPEED_10000:
 327                speed_sel = DW_USXGMII_10000;
 328                break;
 329        default:
 330                /* Nothing to do here */
 331                return -EINVAL;
 332        }
 333
 334        ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
 335        if (ret < 0)
 336                return ret;
 337
 338        ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_EN);
 339        if (ret < 0)
 340                return ret;
 341
 342        ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
 343        if (ret < 0)
 344                return ret;
 345
 346        ret &= ~DW_USXGMII_SS_MASK;
 347        ret |= speed_sel | DW_USXGMII_FULL;
 348
 349        ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
 350        if (ret < 0)
 351                return ret;
 352
 353        ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
 354        if (ret < 0)
 355                return ret;
 356
 357        return xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST);
 358}
 359
 360static int xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
 361{
 362        int ret, adv;
 363
 364        /* By default, in USXGMII mode XPCS operates at 10G baud and
 365         * replicates data to achieve lower speeds. Hereby, in this
 366         * default configuration we need to advertise all supported
 367         * modes and not only the ones we want to use.
 368         */
 369
 370        /* SR_AN_ADV3 */
 371        adv = 0;
 372        if (phylink_test(xpcs->supported, 2500baseX_Full))
 373                adv |= DW_C73_2500KX;
 374
 375        /* TODO: 5000baseKR */
 376
 377        ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV3, adv);
 378        if (ret < 0)
 379                return ret;
 380
 381        /* SR_AN_ADV2 */
 382        adv = 0;
 383        if (phylink_test(xpcs->supported, 1000baseKX_Full))
 384                adv |= DW_C73_1000KX;
 385        if (phylink_test(xpcs->supported, 10000baseKX4_Full))
 386                adv |= DW_C73_10000KX4;
 387        if (phylink_test(xpcs->supported, 10000baseKR_Full))
 388                adv |= DW_C73_10000KR;
 389
 390        ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV2, adv);
 391        if (ret < 0)
 392                return ret;
 393
 394        /* SR_AN_ADV1 */
 395        adv = DW_C73_AN_ADV_SF;
 396        if (phylink_test(xpcs->supported, Pause))
 397                adv |= DW_C73_PAUSE;
 398        if (phylink_test(xpcs->supported, Asym_Pause))
 399                adv |= DW_C73_ASYM_PAUSE;
 400
 401        return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv);
 402}
 403
 404static int xpcs_config_aneg(struct mdio_xpcs_args *xpcs)
 405{
 406        int ret;
 407
 408        ret = xpcs_config_aneg_c73(xpcs);
 409        if (ret < 0)
 410                return ret;
 411
 412        ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_CTRL1);
 413        if (ret < 0)
 414                return ret;
 415
 416        ret |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART;
 417
 418        return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret);
 419}
 420
 421static int xpcs_aneg_done(struct mdio_xpcs_args *xpcs,
 422                          struct phylink_link_state *state)
 423{
 424        int ret;
 425
 426        ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
 427        if (ret < 0)
 428                return ret;
 429
 430        if (ret & MDIO_AN_STAT1_COMPLETE) {
 431                ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
 432                if (ret < 0)
 433                        return ret;
 434
 435                /* Check if Aneg outcome is valid */
 436                if (!(ret & DW_C73_AN_ADV_SF)) {
 437                        xpcs_config_aneg(xpcs);
 438                        return 0;
 439                }
 440
 441                return 1;
 442        }
 443
 444        return 0;
 445}
 446
 447static int xpcs_read_lpa(struct mdio_xpcs_args *xpcs,
 448                         struct phylink_link_state *state)
 449{
 450        int ret;
 451
 452        ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
 453        if (ret < 0)
 454                return ret;
 455
 456        if (!(ret & MDIO_AN_STAT1_LPABLE)) {
 457                phylink_clear(state->lp_advertising, Autoneg);
 458                return 0;
 459        }
 460
 461        phylink_set(state->lp_advertising, Autoneg);
 462
 463        /* Clause 73 outcome */
 464        ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL3);
 465        if (ret < 0)
 466                return ret;
 467
 468        if (ret & DW_C73_2500KX)
 469                phylink_set(state->lp_advertising, 2500baseX_Full);
 470
 471        ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL2);
 472        if (ret < 0)
 473                return ret;
 474
 475        if (ret & DW_C73_1000KX)
 476                phylink_set(state->lp_advertising, 1000baseKX_Full);
 477        if (ret & DW_C73_10000KX4)
 478                phylink_set(state->lp_advertising, 10000baseKX4_Full);
 479        if (ret & DW_C73_10000KR)
 480                phylink_set(state->lp_advertising, 10000baseKR_Full);
 481
 482        ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
 483        if (ret < 0)
 484                return ret;
 485
 486        if (ret & DW_C73_PAUSE)
 487                phylink_set(state->lp_advertising, Pause);
 488        if (ret & DW_C73_ASYM_PAUSE)
 489                phylink_set(state->lp_advertising, Asym_Pause);
 490
 491        linkmode_and(state->lp_advertising, state->lp_advertising,
 492                     state->advertising);
 493        return 0;
 494}
 495
 496static void xpcs_resolve_lpa(struct mdio_xpcs_args *xpcs,
 497                             struct phylink_link_state *state)
 498{
 499        int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising);
 500
 501        state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
 502        state->speed = max_speed;
 503        state->duplex = DUPLEX_FULL;
 504}
 505
 506static int xpcs_get_max_xlgmii_speed(struct mdio_xpcs_args *xpcs,
 507                                     struct phylink_link_state *state)
 508{
 509        unsigned long *adv = state->advertising;
 510        int speed = SPEED_UNKNOWN;
 511        int bit;
 512
 513        for_each_set_bit(bit, adv, __ETHTOOL_LINK_MODE_MASK_NBITS) {
 514                int new_speed = SPEED_UNKNOWN;
 515
 516                switch (bit) {
 517                case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT:
 518                case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT:
 519                case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT:
 520                        new_speed = SPEED_25000;
 521                        break;
 522                case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT:
 523                case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT:
 524                case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT:
 525                case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT:
 526                        new_speed = SPEED_40000;
 527                        break;
 528                case ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT:
 529                case ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT:
 530                case ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT:
 531                case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT:
 532                case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT:
 533                case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT:
 534                case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT:
 535                case ETHTOOL_LINK_MODE_50000baseDR_Full_BIT:
 536                        new_speed = SPEED_50000;
 537                        break;
 538                case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT:
 539                case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT:
 540                case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT:
 541                case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT:
 542                case ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT:
 543                case ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT:
 544                case ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT:
 545                case ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT:
 546                case ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT:
 547                        new_speed = SPEED_100000;
 548                        break;
 549                default:
 550                        continue;
 551                }
 552
 553                if (new_speed > speed)
 554                        speed = new_speed;
 555        }
 556
 557        return speed;
 558}
 559
 560static void xpcs_resolve_pma(struct mdio_xpcs_args *xpcs,
 561                             struct phylink_link_state *state)
 562{
 563        state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
 564        state->duplex = DUPLEX_FULL;
 565
 566        switch (state->interface) {
 567        case PHY_INTERFACE_MODE_10GKR:
 568                state->speed = SPEED_10000;
 569                break;
 570        case PHY_INTERFACE_MODE_XLGMII:
 571                state->speed = xpcs_get_max_xlgmii_speed(xpcs, state);
 572                break;
 573        default:
 574                state->speed = SPEED_UNKNOWN;
 575                break;
 576        }
 577}
 578
 579static int xpcs_validate(struct mdio_xpcs_args *xpcs,
 580                         unsigned long *supported,
 581                         struct phylink_link_state *state)
 582{
 583        linkmode_and(supported, supported, xpcs->supported);
 584        linkmode_and(state->advertising, state->advertising, xpcs->supported);
 585        return 0;
 586}
 587
 588static int xpcs_config(struct mdio_xpcs_args *xpcs,
 589                       const struct phylink_link_state *state)
 590{
 591        int ret;
 592
 593        if (state->an_enabled) {
 594                ret = xpcs_config_aneg(xpcs);
 595                if (ret)
 596                        return ret;
 597        }
 598
 599        return 0;
 600}
 601
 602static int xpcs_get_state(struct mdio_xpcs_args *xpcs,
 603                          struct phylink_link_state *state)
 604{
 605        int ret;
 606
 607        /* Link needs to be read first ... */
 608        state->link = xpcs_read_link(xpcs, state->an_enabled) > 0 ? 1 : 0;
 609
 610        /* ... and then we check the faults. */
 611        ret = xpcs_read_fault(xpcs, state);
 612        if (ret) {
 613                ret = xpcs_soft_reset(xpcs, MDIO_MMD_PCS);
 614                if (ret)
 615                        return ret;
 616
 617                state->link = 0;
 618
 619                return xpcs_config(xpcs, state);
 620        }
 621
 622        if (state->an_enabled && xpcs_aneg_done(xpcs, state)) {
 623                state->an_complete = true;
 624                xpcs_read_lpa(xpcs, state);
 625                xpcs_resolve_lpa(xpcs, state);
 626        } else if (state->an_enabled) {
 627                state->link = 0;
 628        } else if (state->link) {
 629                xpcs_resolve_pma(xpcs, state);
 630        }
 631
 632        return 0;
 633}
 634
 635static int xpcs_link_up(struct mdio_xpcs_args *xpcs, int speed,
 636                        phy_interface_t interface)
 637{
 638        if (interface == PHY_INTERFACE_MODE_USXGMII)
 639                return xpcs_config_usxgmii(xpcs, speed);
 640
 641        return 0;
 642}
 643
 644static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
 645{
 646        int ret;
 647        u32 id;
 648
 649        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
 650        if (ret < 0)
 651                return 0xffffffff;
 652
 653        id = ret << 16;
 654
 655        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID2);
 656        if (ret < 0)
 657                return 0xffffffff;
 658
 659        return id | ret;
 660}
 661
 662static bool xpcs_check_features(struct mdio_xpcs_args *xpcs,
 663                                struct xpcs_id *match,
 664                                phy_interface_t interface)
 665{
 666        int i;
 667
 668        for (i = 0; match->interface[i] != PHY_INTERFACE_MODE_MAX; i++) {
 669                if (match->interface[i] == interface)
 670                        break;
 671        }
 672
 673        if (match->interface[i] == PHY_INTERFACE_MODE_MAX)
 674                return false;
 675
 676        for (i = 0; match->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
 677                set_bit(match->supported[i], xpcs->supported);
 678
 679        return true;
 680}
 681
 682static int xpcs_probe(struct mdio_xpcs_args *xpcs, phy_interface_t interface)
 683{
 684        u32 xpcs_id = xpcs_get_id(xpcs);
 685        struct xpcs_id *match = NULL;
 686        int i;
 687
 688        for (i = 0; i < ARRAY_SIZE(xpcs_id_list); i++) {
 689                struct xpcs_id *entry = &xpcs_id_list[i];
 690
 691                if ((xpcs_id & entry->mask) == entry->id) {
 692                        match = entry;
 693
 694                        if (xpcs_check_features(xpcs, match, interface))
 695                                return xpcs_soft_reset(xpcs, MDIO_MMD_PCS);
 696                }
 697        }
 698
 699        return -ENODEV;
 700}
 701
 702static struct mdio_xpcs_ops xpcs_ops = {
 703        .validate = xpcs_validate,
 704        .config = xpcs_config,
 705        .get_state = xpcs_get_state,
 706        .link_up = xpcs_link_up,
 707        .probe = xpcs_probe,
 708};
 709
 710struct mdio_xpcs_ops *mdio_xpcs_get_ops(void)
 711{
 712        return &xpcs_ops;
 713}
 714EXPORT_SYMBOL_GPL(mdio_xpcs_get_ops);
 715
 716MODULE_LICENSE("GPL v2");
 717