linux/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
   2/* Copyright 2019 NXP */
   3
   4#include <linux/acpi.h>
   5#include <linux/property.h>
   6
   7#include "dpaa2-eth.h"
   8#include "dpaa2-mac.h"
   9
  10#define phylink_to_dpaa2_mac(config) \
  11        container_of((config), struct dpaa2_mac, phylink_config)
  12
  13static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
  14{
  15        *if_mode = PHY_INTERFACE_MODE_NA;
  16
  17        switch (eth_if) {
  18        case DPMAC_ETH_IF_RGMII:
  19                *if_mode = PHY_INTERFACE_MODE_RGMII;
  20                break;
  21        case DPMAC_ETH_IF_USXGMII:
  22                *if_mode = PHY_INTERFACE_MODE_USXGMII;
  23                break;
  24        case DPMAC_ETH_IF_QSGMII:
  25                *if_mode = PHY_INTERFACE_MODE_QSGMII;
  26                break;
  27        case DPMAC_ETH_IF_SGMII:
  28                *if_mode = PHY_INTERFACE_MODE_SGMII;
  29                break;
  30        case DPMAC_ETH_IF_XFI:
  31                *if_mode = PHY_INTERFACE_MODE_10GBASER;
  32                break;
  33        default:
  34                return -EINVAL;
  35        }
  36
  37        return 0;
  38}
  39
  40static struct fwnode_handle *dpaa2_mac_get_node(struct device *dev,
  41                                                u16 dpmac_id)
  42{
  43        struct fwnode_handle *fwnode, *parent, *child  = NULL;
  44        struct device_node *dpmacs = NULL;
  45        int err;
  46        u32 id;
  47
  48        fwnode = dev_fwnode(dev->parent);
  49        if (is_of_node(fwnode)) {
  50                dpmacs = of_find_node_by_name(NULL, "dpmacs");
  51                if (!dpmacs)
  52                        return NULL;
  53                parent = of_fwnode_handle(dpmacs);
  54        } else if (is_acpi_node(fwnode)) {
  55                parent = fwnode;
  56        }
  57
  58        fwnode_for_each_child_node(parent, child) {
  59                err = -EINVAL;
  60                if (is_acpi_device_node(child))
  61                        err = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &id);
  62                else if (is_of_node(child))
  63                        err = of_property_read_u32(to_of_node(child), "reg", &id);
  64                if (err)
  65                        continue;
  66
  67                if (id == dpmac_id) {
  68                        of_node_put(dpmacs);
  69                        return child;
  70                }
  71        }
  72        of_node_put(dpmacs);
  73        return NULL;
  74}
  75
  76static int dpaa2_mac_get_if_mode(struct fwnode_handle *dpmac_node,
  77                                 struct dpmac_attr attr)
  78{
  79        phy_interface_t if_mode;
  80        int err;
  81
  82        err = fwnode_get_phy_mode(dpmac_node);
  83        if (err > 0)
  84                return err;
  85
  86        err = phy_mode(attr.eth_if, &if_mode);
  87        if (!err)
  88                return if_mode;
  89
  90        return err;
  91}
  92
  93static bool dpaa2_mac_phy_mode_mismatch(struct dpaa2_mac *mac,
  94                                        phy_interface_t interface)
  95{
  96        switch (interface) {
  97        /* We can switch between SGMII and 1000BASE-X at runtime with
  98         * pcs-lynx
  99         */
 100        case PHY_INTERFACE_MODE_SGMII:
 101        case PHY_INTERFACE_MODE_1000BASEX:
 102                if (mac->pcs &&
 103                    (mac->if_mode == PHY_INTERFACE_MODE_SGMII ||
 104                     mac->if_mode == PHY_INTERFACE_MODE_1000BASEX))
 105                        return false;
 106                return interface != mac->if_mode;
 107
 108        case PHY_INTERFACE_MODE_10GBASER:
 109        case PHY_INTERFACE_MODE_USXGMII:
 110        case PHY_INTERFACE_MODE_QSGMII:
 111        case PHY_INTERFACE_MODE_RGMII:
 112        case PHY_INTERFACE_MODE_RGMII_ID:
 113        case PHY_INTERFACE_MODE_RGMII_RXID:
 114        case PHY_INTERFACE_MODE_RGMII_TXID:
 115                return (interface != mac->if_mode);
 116        default:
 117                return true;
 118        }
 119}
 120
 121static void dpaa2_mac_validate(struct phylink_config *config,
 122                               unsigned long *supported,
 123                               struct phylink_link_state *state)
 124{
 125        struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
 126        __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 127
 128        if (state->interface != PHY_INTERFACE_MODE_NA &&
 129            dpaa2_mac_phy_mode_mismatch(mac, state->interface)) {
 130                goto empty_set;
 131        }
 132
 133        phylink_set_port_modes(mask);
 134        phylink_set(mask, Autoneg);
 135        phylink_set(mask, Pause);
 136        phylink_set(mask, Asym_Pause);
 137
 138        switch (state->interface) {
 139        case PHY_INTERFACE_MODE_NA:
 140        case PHY_INTERFACE_MODE_10GBASER:
 141        case PHY_INTERFACE_MODE_USXGMII:
 142                phylink_set(mask, 10000baseT_Full);
 143                if (state->interface == PHY_INTERFACE_MODE_10GBASER)
 144                        break;
 145                phylink_set(mask, 5000baseT_Full);
 146                phylink_set(mask, 2500baseT_Full);
 147                fallthrough;
 148        case PHY_INTERFACE_MODE_SGMII:
 149        case PHY_INTERFACE_MODE_QSGMII:
 150        case PHY_INTERFACE_MODE_1000BASEX:
 151        case PHY_INTERFACE_MODE_RGMII:
 152        case PHY_INTERFACE_MODE_RGMII_ID:
 153        case PHY_INTERFACE_MODE_RGMII_RXID:
 154        case PHY_INTERFACE_MODE_RGMII_TXID:
 155                phylink_set(mask, 1000baseX_Full);
 156                phylink_set(mask, 1000baseT_Full);
 157                if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
 158                        break;
 159                phylink_set(mask, 100baseT_Full);
 160                phylink_set(mask, 10baseT_Full);
 161                break;
 162        default:
 163                goto empty_set;
 164        }
 165
 166        linkmode_and(supported, supported, mask);
 167        linkmode_and(state->advertising, state->advertising, mask);
 168
 169        return;
 170
 171empty_set:
 172        linkmode_zero(supported);
 173}
 174
 175static void dpaa2_mac_config(struct phylink_config *config, unsigned int mode,
 176                             const struct phylink_link_state *state)
 177{
 178        struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
 179        struct dpmac_link_state *dpmac_state = &mac->state;
 180        int err;
 181
 182        if (state->an_enabled)
 183                dpmac_state->options |= DPMAC_LINK_OPT_AUTONEG;
 184        else
 185                dpmac_state->options &= ~DPMAC_LINK_OPT_AUTONEG;
 186
 187        err = dpmac_set_link_state(mac->mc_io, 0,
 188                                   mac->mc_dev->mc_handle, dpmac_state);
 189        if (err)
 190                netdev_err(mac->net_dev, "%s: dpmac_set_link_state() = %d\n",
 191                           __func__, err);
 192}
 193
 194static void dpaa2_mac_link_up(struct phylink_config *config,
 195                              struct phy_device *phy,
 196                              unsigned int mode, phy_interface_t interface,
 197                              int speed, int duplex,
 198                              bool tx_pause, bool rx_pause)
 199{
 200        struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
 201        struct dpmac_link_state *dpmac_state = &mac->state;
 202        int err;
 203
 204        dpmac_state->up = 1;
 205
 206        dpmac_state->rate = speed;
 207
 208        if (duplex == DUPLEX_HALF)
 209                dpmac_state->options |= DPMAC_LINK_OPT_HALF_DUPLEX;
 210        else if (duplex == DUPLEX_FULL)
 211                dpmac_state->options &= ~DPMAC_LINK_OPT_HALF_DUPLEX;
 212
 213        if (rx_pause)
 214                dpmac_state->options |= DPMAC_LINK_OPT_PAUSE;
 215        else
 216                dpmac_state->options &= ~DPMAC_LINK_OPT_PAUSE;
 217
 218        if (rx_pause ^ tx_pause)
 219                dpmac_state->options |= DPMAC_LINK_OPT_ASYM_PAUSE;
 220        else
 221                dpmac_state->options &= ~DPMAC_LINK_OPT_ASYM_PAUSE;
 222
 223        err = dpmac_set_link_state(mac->mc_io, 0,
 224                                   mac->mc_dev->mc_handle, dpmac_state);
 225        if (err)
 226                netdev_err(mac->net_dev, "%s: dpmac_set_link_state() = %d\n",
 227                           __func__, err);
 228}
 229
 230static void dpaa2_mac_link_down(struct phylink_config *config,
 231                                unsigned int mode,
 232                                phy_interface_t interface)
 233{
 234        struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
 235        struct dpmac_link_state *dpmac_state = &mac->state;
 236        int err;
 237
 238        dpmac_state->up = 0;
 239        err = dpmac_set_link_state(mac->mc_io, 0,
 240                                   mac->mc_dev->mc_handle, dpmac_state);
 241        if (err)
 242                netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err);
 243}
 244
 245static const struct phylink_mac_ops dpaa2_mac_phylink_ops = {
 246        .validate = dpaa2_mac_validate,
 247        .mac_config = dpaa2_mac_config,
 248        .mac_link_up = dpaa2_mac_link_up,
 249        .mac_link_down = dpaa2_mac_link_down,
 250};
 251
 252static int dpaa2_pcs_create(struct dpaa2_mac *mac,
 253                            struct fwnode_handle *dpmac_node,
 254                            int id)
 255{
 256        struct mdio_device *mdiodev;
 257        struct fwnode_handle *node;
 258
 259        node = fwnode_find_reference(dpmac_node, "pcs-handle", 0);
 260        if (IS_ERR(node)) {
 261                /* do not error out on old DTS files */
 262                netdev_warn(mac->net_dev, "pcs-handle node not found\n");
 263                return 0;
 264        }
 265
 266        if (!fwnode_device_is_available(node)) {
 267                netdev_err(mac->net_dev, "pcs-handle node not available\n");
 268                fwnode_handle_put(node);
 269                return -ENODEV;
 270        }
 271
 272        mdiodev = fwnode_mdio_find_device(node);
 273        fwnode_handle_put(node);
 274        if (!mdiodev)
 275                return -EPROBE_DEFER;
 276
 277        mac->pcs = lynx_pcs_create(mdiodev);
 278        if (!mac->pcs) {
 279                netdev_err(mac->net_dev, "lynx_pcs_create() failed\n");
 280                put_device(&mdiodev->dev);
 281                return -ENOMEM;
 282        }
 283
 284        return 0;
 285}
 286
 287static void dpaa2_pcs_destroy(struct dpaa2_mac *mac)
 288{
 289        struct lynx_pcs *pcs = mac->pcs;
 290
 291        if (pcs) {
 292                struct device *dev = &pcs->mdio->dev;
 293                lynx_pcs_destroy(pcs);
 294                put_device(dev);
 295                mac->pcs = NULL;
 296        }
 297}
 298
 299int dpaa2_mac_connect(struct dpaa2_mac *mac)
 300{
 301        struct net_device *net_dev = mac->net_dev;
 302        struct fwnode_handle *dpmac_node;
 303        struct phylink *phylink;
 304        int err;
 305
 306        mac->if_link_type = mac->attr.link_type;
 307
 308        dpmac_node = mac->fw_node;
 309        if (!dpmac_node) {
 310                netdev_err(net_dev, "No dpmac@%d node found.\n", mac->attr.id);
 311                return -ENODEV;
 312        }
 313
 314        err = dpaa2_mac_get_if_mode(dpmac_node, mac->attr);
 315        if (err < 0)
 316                return -EINVAL;
 317        mac->if_mode = err;
 318
 319        /* The MAC does not have the capability to add RGMII delays so
 320         * error out if the interface mode requests them and there is no PHY
 321         * to act upon them
 322         */
 323        if (of_phy_is_fixed_link(to_of_node(dpmac_node)) &&
 324            (mac->if_mode == PHY_INTERFACE_MODE_RGMII_ID ||
 325             mac->if_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
 326             mac->if_mode == PHY_INTERFACE_MODE_RGMII_TXID)) {
 327                netdev_err(net_dev, "RGMII delay not supported\n");
 328                return -EINVAL;
 329        }
 330
 331        if ((mac->attr.link_type == DPMAC_LINK_TYPE_PHY &&
 332             mac->attr.eth_if != DPMAC_ETH_IF_RGMII) ||
 333            mac->attr.link_type == DPMAC_LINK_TYPE_BACKPLANE) {
 334                err = dpaa2_pcs_create(mac, dpmac_node, mac->attr.id);
 335                if (err)
 336                        return err;
 337        }
 338
 339        mac->phylink_config.dev = &net_dev->dev;
 340        mac->phylink_config.type = PHYLINK_NETDEV;
 341
 342        phylink = phylink_create(&mac->phylink_config,
 343                                 dpmac_node, mac->if_mode,
 344                                 &dpaa2_mac_phylink_ops);
 345        if (IS_ERR(phylink)) {
 346                err = PTR_ERR(phylink);
 347                goto err_pcs_destroy;
 348        }
 349        mac->phylink = phylink;
 350
 351        if (mac->pcs)
 352                phylink_set_pcs(mac->phylink, &mac->pcs->pcs);
 353
 354        err = phylink_fwnode_phy_connect(mac->phylink, dpmac_node, 0);
 355        if (err) {
 356                netdev_err(net_dev, "phylink_fwnode_phy_connect() = %d\n", err);
 357                goto err_phylink_destroy;
 358        }
 359
 360        return 0;
 361
 362err_phylink_destroy:
 363        phylink_destroy(mac->phylink);
 364err_pcs_destroy:
 365        dpaa2_pcs_destroy(mac);
 366
 367        return err;
 368}
 369
 370void dpaa2_mac_disconnect(struct dpaa2_mac *mac)
 371{
 372        if (!mac->phylink)
 373                return;
 374
 375        phylink_disconnect_phy(mac->phylink);
 376        phylink_destroy(mac->phylink);
 377        dpaa2_pcs_destroy(mac);
 378}
 379
 380int dpaa2_mac_open(struct dpaa2_mac *mac)
 381{
 382        struct fsl_mc_device *dpmac_dev = mac->mc_dev;
 383        struct net_device *net_dev = mac->net_dev;
 384        int err;
 385
 386        err = dpmac_open(mac->mc_io, 0, dpmac_dev->obj_desc.id,
 387                         &dpmac_dev->mc_handle);
 388        if (err || !dpmac_dev->mc_handle) {
 389                netdev_err(net_dev, "dpmac_open() = %d\n", err);
 390                return -ENODEV;
 391        }
 392
 393        err = dpmac_get_attributes(mac->mc_io, 0, dpmac_dev->mc_handle,
 394                                   &mac->attr);
 395        if (err) {
 396                netdev_err(net_dev, "dpmac_get_attributes() = %d\n", err);
 397                goto err_close_dpmac;
 398        }
 399
 400        /* Find the device node representing the MAC device and link the device
 401         * behind the associated netdev to it.
 402         */
 403        mac->fw_node = dpaa2_mac_get_node(&mac->mc_dev->dev, mac->attr.id);
 404        net_dev->dev.of_node = to_of_node(mac->fw_node);
 405
 406        return 0;
 407
 408err_close_dpmac:
 409        dpmac_close(mac->mc_io, 0, dpmac_dev->mc_handle);
 410        return err;
 411}
 412
 413void dpaa2_mac_close(struct dpaa2_mac *mac)
 414{
 415        struct fsl_mc_device *dpmac_dev = mac->mc_dev;
 416
 417        dpmac_close(mac->mc_io, 0, dpmac_dev->mc_handle);
 418        if (mac->fw_node)
 419                fwnode_handle_put(mac->fw_node);
 420}
 421
 422static char dpaa2_mac_ethtool_stats[][ETH_GSTRING_LEN] = {
 423        [DPMAC_CNT_ING_ALL_FRAME]               = "[mac] rx all frames",
 424        [DPMAC_CNT_ING_GOOD_FRAME]              = "[mac] rx frames ok",
 425        [DPMAC_CNT_ING_ERR_FRAME]               = "[mac] rx frame errors",
 426        [DPMAC_CNT_ING_FRAME_DISCARD]           = "[mac] rx frame discards",
 427        [DPMAC_CNT_ING_UCAST_FRAME]             = "[mac] rx u-cast",
 428        [DPMAC_CNT_ING_BCAST_FRAME]             = "[mac] rx b-cast",
 429        [DPMAC_CNT_ING_MCAST_FRAME]             = "[mac] rx m-cast",
 430        [DPMAC_CNT_ING_FRAME_64]                = "[mac] rx 64 bytes",
 431        [DPMAC_CNT_ING_FRAME_127]               = "[mac] rx 65-127 bytes",
 432        [DPMAC_CNT_ING_FRAME_255]               = "[mac] rx 128-255 bytes",
 433        [DPMAC_CNT_ING_FRAME_511]               = "[mac] rx 256-511 bytes",
 434        [DPMAC_CNT_ING_FRAME_1023]              = "[mac] rx 512-1023 bytes",
 435        [DPMAC_CNT_ING_FRAME_1518]              = "[mac] rx 1024-1518 bytes",
 436        [DPMAC_CNT_ING_FRAME_1519_MAX]          = "[mac] rx 1519-max bytes",
 437        [DPMAC_CNT_ING_FRAG]                    = "[mac] rx frags",
 438        [DPMAC_CNT_ING_JABBER]                  = "[mac] rx jabber",
 439        [DPMAC_CNT_ING_ALIGN_ERR]               = "[mac] rx align errors",
 440        [DPMAC_CNT_ING_OVERSIZED]               = "[mac] rx oversized",
 441        [DPMAC_CNT_ING_VALID_PAUSE_FRAME]       = "[mac] rx pause",
 442        [DPMAC_CNT_ING_BYTE]                    = "[mac] rx bytes",
 443        [DPMAC_CNT_EGR_GOOD_FRAME]              = "[mac] tx frames ok",
 444        [DPMAC_CNT_EGR_UCAST_FRAME]             = "[mac] tx u-cast",
 445        [DPMAC_CNT_EGR_MCAST_FRAME]             = "[mac] tx m-cast",
 446        [DPMAC_CNT_EGR_BCAST_FRAME]             = "[mac] tx b-cast",
 447        [DPMAC_CNT_EGR_ERR_FRAME]               = "[mac] tx frame errors",
 448        [DPMAC_CNT_EGR_UNDERSIZED]              = "[mac] tx undersized",
 449        [DPMAC_CNT_EGR_VALID_PAUSE_FRAME]       = "[mac] tx b-pause",
 450        [DPMAC_CNT_EGR_BYTE]                    = "[mac] tx bytes",
 451};
 452
 453#define DPAA2_MAC_NUM_STATS     ARRAY_SIZE(dpaa2_mac_ethtool_stats)
 454
 455int dpaa2_mac_get_sset_count(void)
 456{
 457        return DPAA2_MAC_NUM_STATS;
 458}
 459
 460void dpaa2_mac_get_strings(u8 *data)
 461{
 462        u8 *p = data;
 463        int i;
 464
 465        for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) {
 466                strlcpy(p, dpaa2_mac_ethtool_stats[i], ETH_GSTRING_LEN);
 467                p += ETH_GSTRING_LEN;
 468        }
 469}
 470
 471void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data)
 472{
 473        struct fsl_mc_device *dpmac_dev = mac->mc_dev;
 474        int i, err;
 475        u64 value;
 476
 477        for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) {
 478                err = dpmac_get_counter(mac->mc_io, 0, dpmac_dev->mc_handle,
 479                                        i, &value);
 480                if (err) {
 481                        netdev_err_once(mac->net_dev,
 482                                        "dpmac_get_counter error %d\n", err);
 483                        *(data + i) = U64_MAX;
 484                        continue;
 485                }
 486                *(data + i) = value;
 487        }
 488}
 489