uboot/net/dsa-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2019-2021 NXP
   4 */
   5
   6#include <net/dsa.h>
   7#include <dm/lists.h>
   8#include <dm/device_compat.h>
   9#include <dm/device-internal.h>
  10#include <dm/uclass-internal.h>
  11#include <linux/bitmap.h>
  12#include <miiphy.h>
  13
  14#define DSA_PORT_CHILD_DRV_NAME "dsa-port"
  15
  16/* per-device internal state structure */
  17struct dsa_priv {
  18        struct phy_device *cpu_port_fixed_phy;
  19        struct udevice *master_dev;
  20        int num_ports;
  21        u32 cpu_port;
  22        int headroom;
  23        int tailroom;
  24};
  25
  26/* external API */
  27int dsa_set_tagging(struct udevice *dev, ushort headroom, ushort tailroom)
  28{
  29        struct dsa_priv *priv;
  30
  31        if (!dev)
  32                return -EINVAL;
  33
  34        if (headroom + tailroom > DSA_MAX_OVR)
  35                return -EINVAL;
  36
  37        priv = dev_get_uclass_priv(dev);
  38
  39        if (headroom > 0)
  40                priv->headroom = headroom;
  41        if (tailroom > 0)
  42                priv->tailroom = tailroom;
  43
  44        return 0;
  45}
  46
  47/* returns the DSA master Ethernet device */
  48struct udevice *dsa_get_master(struct udevice *dev)
  49{
  50        struct dsa_priv *priv;
  51
  52        if (!dev)
  53                return NULL;
  54
  55        priv = dev_get_uclass_priv(dev);
  56
  57        return priv->master_dev;
  58}
  59
  60/*
  61 * Start the desired port, the CPU port and the master Eth interface.
  62 * TODO: if cascaded we may need to _start ports in other switches too
  63 */
  64static int dsa_port_start(struct udevice *pdev)
  65{
  66        struct udevice *dev = dev_get_parent(pdev);
  67        struct dsa_priv *priv = dev_get_uclass_priv(dev);
  68        struct udevice *master = dsa_get_master(dev);
  69        struct dsa_ops *ops = dsa_get_ops(dev);
  70        int err;
  71
  72        if (ops->port_enable) {
  73                struct dsa_port_pdata *port_pdata;
  74
  75                port_pdata = dev_get_parent_plat(pdev);
  76                err = ops->port_enable(dev, port_pdata->index,
  77                                       port_pdata->phy);
  78                if (err)
  79                        return err;
  80
  81                err = ops->port_enable(dev, priv->cpu_port,
  82                                       priv->cpu_port_fixed_phy);
  83                if (err)
  84                        return err;
  85        }
  86
  87        return eth_get_ops(master)->start(master);
  88}
  89
  90/* Stop the desired port, the CPU port and the master Eth interface */
  91static void dsa_port_stop(struct udevice *pdev)
  92{
  93        struct udevice *dev = dev_get_parent(pdev);
  94        struct dsa_priv *priv = dev_get_uclass_priv(dev);
  95        struct udevice *master = dsa_get_master(dev);
  96        struct dsa_ops *ops = dsa_get_ops(dev);
  97
  98        if (ops->port_disable) {
  99                struct dsa_port_pdata *port_pdata;
 100
 101                port_pdata = dev_get_parent_plat(pdev);
 102                ops->port_disable(dev, port_pdata->index, port_pdata->phy);
 103                ops->port_disable(dev, priv->cpu_port, NULL);
 104        }
 105
 106        eth_get_ops(master)->stop(master);
 107}
 108
 109/*
 110 * Insert a DSA tag and call master Ethernet send on the resulting packet
 111 * We copy the frame to a stack buffer where we have reserved headroom and
 112 * tailroom space.  Headroom and tailroom are set to 0.
 113 */
 114static int dsa_port_send(struct udevice *pdev, void *packet, int length)
 115{
 116        struct udevice *dev = dev_get_parent(pdev);
 117        struct dsa_priv *priv = dev_get_uclass_priv(dev);
 118        int head = priv->headroom, tail = priv->tailroom;
 119        struct udevice *master = dsa_get_master(dev);
 120        struct dsa_ops *ops = dsa_get_ops(dev);
 121        uchar dsa_packet_tmp[PKTSIZE_ALIGN];
 122        struct dsa_port_pdata *port_pdata;
 123        int err;
 124
 125        if (length + head + tail > PKTSIZE_ALIGN)
 126                return -EINVAL;
 127
 128        memset(dsa_packet_tmp, 0, head);
 129        memset(dsa_packet_tmp + head + length, 0, tail);
 130        memcpy(dsa_packet_tmp + head, packet, length);
 131        length += head + tail;
 132        /* copy back to preserve original buffer alignment */
 133        memcpy(packet, dsa_packet_tmp, length);
 134
 135        port_pdata = dev_get_parent_plat(pdev);
 136        err = ops->xmit(dev, port_pdata->index, packet, length);
 137        if (err)
 138                return err;
 139
 140        return eth_get_ops(master)->send(master, packet, length);
 141}
 142
 143/* Receive a frame from master Ethernet, process it and pass it on */
 144static int dsa_port_recv(struct udevice *pdev, int flags, uchar **packetp)
 145{
 146        struct udevice *dev = dev_get_parent(pdev);
 147        struct dsa_priv *priv = dev_get_uclass_priv(dev);
 148        int head = priv->headroom, tail = priv->tailroom;
 149        struct udevice *master = dsa_get_master(dev);
 150        struct dsa_ops *ops = dsa_get_ops(dev);
 151        struct dsa_port_pdata *port_pdata;
 152        int length, port_index, err;
 153
 154        length = eth_get_ops(master)->recv(master, flags, packetp);
 155        if (length <= 0)
 156                return length;
 157
 158        /*
 159         * If we receive frames from a different port or frames that DSA driver
 160         * doesn't like we discard them here.
 161         * In case of discard we return with no frame and expect to be called
 162         * again instead of looping here, so upper layer can deal with timeouts.
 163         */
 164        port_pdata = dev_get_parent_plat(pdev);
 165        err = ops->rcv(dev, &port_index, *packetp, length);
 166        if (err || port_index != port_pdata->index || (length <= head + tail)) {
 167                if (eth_get_ops(master)->free_pkt)
 168                        eth_get_ops(master)->free_pkt(master, *packetp, length);
 169                return -EAGAIN;
 170        }
 171
 172        /*
 173         * We move the pointer over headroom here to avoid a copy.  If free_pkt
 174         * gets called we move the pointer back before calling master free_pkt.
 175         */
 176        *packetp += head;
 177
 178        return length - head - tail;
 179}
 180
 181static int dsa_port_free_pkt(struct udevice *pdev, uchar *packet, int length)
 182{
 183        struct udevice *dev = dev_get_parent(pdev);
 184        struct udevice *master = dsa_get_master(dev);
 185        struct dsa_priv *priv;
 186
 187        priv = dev_get_uclass_priv(dev);
 188        if (eth_get_ops(master)->free_pkt) {
 189                /* return the original pointer and length to master Eth */
 190                packet -= priv->headroom;
 191                length += priv->headroom - priv->tailroom;
 192
 193                return eth_get_ops(master)->free_pkt(master, packet, length);
 194        }
 195
 196        return 0;
 197}
 198
 199static int dsa_port_of_to_pdata(struct udevice *pdev)
 200{
 201        struct dsa_port_pdata *port_pdata;
 202        struct dsa_pdata *dsa_pdata;
 203        struct eth_pdata *eth_pdata;
 204        struct udevice *dev;
 205        const char *label;
 206        u32 index;
 207        int err;
 208
 209        if (!pdev)
 210                return -ENODEV;
 211
 212        err = ofnode_read_u32(dev_ofnode(pdev), "reg", &index);
 213        if (err)
 214                return err;
 215
 216        dev = dev_get_parent(pdev);
 217        dsa_pdata = dev_get_uclass_plat(dev);
 218
 219        port_pdata = dev_get_parent_plat(pdev);
 220        port_pdata->index = index;
 221
 222        label = ofnode_read_string(dev_ofnode(pdev), "label");
 223        if (label)
 224                strncpy(port_pdata->name, label, DSA_PORT_NAME_LENGTH);
 225
 226        eth_pdata = dev_get_plat(pdev);
 227        eth_pdata->priv_pdata = port_pdata;
 228
 229        dev_dbg(pdev, "port %d node %s\n", port_pdata->index,
 230                ofnode_get_name(dev_ofnode(pdev)));
 231
 232        return 0;
 233}
 234
 235static const struct eth_ops dsa_port_ops = {
 236        .start          = dsa_port_start,
 237        .send           = dsa_port_send,
 238        .recv           = dsa_port_recv,
 239        .stop           = dsa_port_stop,
 240        .free_pkt       = dsa_port_free_pkt,
 241};
 242
 243static int dsa_port_probe(struct udevice *pdev)
 244{
 245        struct udevice *dev = dev_get_parent(pdev);
 246        struct eth_pdata *eth_pdata, *master_pdata;
 247        unsigned char env_enetaddr[ARP_HLEN];
 248        struct dsa_port_pdata *port_pdata;
 249        struct dsa_priv *dsa_priv;
 250        struct udevice *master;
 251        int ret;
 252
 253        port_pdata = dev_get_parent_plat(pdev);
 254        dsa_priv = dev_get_uclass_priv(dev);
 255
 256        port_pdata->phy = dm_eth_phy_connect(pdev);
 257        if (!port_pdata->phy)
 258                return -ENODEV;
 259
 260        master = dsa_get_master(dev);
 261        if (!master)
 262                return -ENODEV;
 263
 264        /*
 265         * Probe the master device. We depend on the master device for proper
 266         * operation and we also need it for MAC inheritance below.
 267         *
 268         * TODO: we assume the master device is always there and doesn't get
 269         * removed during runtime.
 270         */
 271        ret = device_probe(master);
 272        if (ret)
 273                return ret;
 274
 275        /*
 276         * Inherit port's hwaddr from the DSA master, unless the port already
 277         * has a unique MAC address specified in the environment.
 278         */
 279        eth_env_get_enetaddr_by_index("eth", dev_seq(pdev), env_enetaddr);
 280        if (!is_zero_ethaddr(env_enetaddr)) {
 281                /* individual port mac addrs require master to be promisc */
 282                struct eth_ops *eth_ops = eth_get_ops(master);
 283
 284                if (eth_ops->set_promisc)
 285                        eth_ops->set_promisc(master, 1);
 286
 287                return 0;
 288        }
 289
 290        master_pdata = dev_get_plat(master);
 291        eth_pdata = dev_get_plat(pdev);
 292        memcpy(eth_pdata->enetaddr, master_pdata->enetaddr, ARP_HLEN);
 293        eth_env_set_enetaddr_by_index("eth", dev_seq(pdev),
 294                                      master_pdata->enetaddr);
 295
 296        return 0;
 297}
 298
 299static int dsa_port_remove(struct udevice *pdev)
 300{
 301        struct udevice *dev = dev_get_parent(pdev);
 302        struct dsa_port_pdata *port_pdata;
 303        struct dsa_priv *dsa_priv;
 304
 305        port_pdata = dev_get_parent_plat(pdev);
 306        dsa_priv = dev_get_uclass_priv(dev);
 307
 308        port_pdata->phy = NULL;
 309
 310        return 0;
 311}
 312
 313U_BOOT_DRIVER(dsa_port) = {
 314        .name   = DSA_PORT_CHILD_DRV_NAME,
 315        .id     = UCLASS_ETH,
 316        .ops    = &dsa_port_ops,
 317        .probe  = dsa_port_probe,
 318        .remove = dsa_port_remove,
 319        .of_to_plat = dsa_port_of_to_pdata,
 320        .plat_auto = sizeof(struct eth_pdata),
 321};
 322
 323/*
 324 * This function mostly deals with pulling information out of the device tree
 325 * into the pdata structure.
 326 * It goes through the list of switch ports, registers an eth device for each
 327 * front panel port and identifies the cpu port connected to master eth device.
 328 * TODO: support cascaded switches
 329 */
 330static int dsa_post_bind(struct udevice *dev)
 331{
 332        struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
 333        ofnode node = dev_ofnode(dev), pnode;
 334        int i, err, first_err = 0;
 335
 336        if (!ofnode_valid(node))
 337                return -ENODEV;
 338
 339        pdata->master_node = ofnode_null();
 340
 341        node = ofnode_find_subnode(node, "ports");
 342        if (!ofnode_valid(node))
 343                node = ofnode_find_subnode(node, "ethernet-ports");
 344        if (!ofnode_valid(node)) {
 345                dev_err(dev, "ports node is missing under DSA device!\n");
 346                return -EINVAL;
 347        }
 348
 349        pdata->num_ports = ofnode_get_child_count(node);
 350        if (pdata->num_ports <= 0 || pdata->num_ports > DSA_MAX_PORTS) {
 351                dev_err(dev, "invalid number of ports (%d)\n",
 352                        pdata->num_ports);
 353                return -EINVAL;
 354        }
 355
 356        /* look for the CPU port */
 357        ofnode_for_each_subnode(pnode, node) {
 358                u32 ethernet;
 359
 360                if (ofnode_read_u32(pnode, "ethernet", &ethernet))
 361                        continue;
 362
 363                pdata->master_node = ofnode_get_by_phandle(ethernet);
 364                pdata->cpu_port_node = pnode;
 365                break;
 366        }
 367
 368        if (!ofnode_valid(pdata->master_node)) {
 369                dev_err(dev, "master eth node missing!\n");
 370                return -EINVAL;
 371        }
 372
 373        if (ofnode_read_u32(pnode, "reg", &pdata->cpu_port)) {
 374                dev_err(dev, "CPU port node not valid!\n");
 375                return -EINVAL;
 376        }
 377
 378        dev_dbg(dev, "master node %s on port %d\n",
 379                ofnode_get_name(pdata->master_node), pdata->cpu_port);
 380
 381        for (i = 0; i < pdata->num_ports; i++) {
 382                char name[DSA_PORT_NAME_LENGTH];
 383                struct udevice *pdev;
 384
 385                /*
 386                 * If this is the CPU port don't register it as an ETH device,
 387                 * we skip it on purpose since I/O to/from it from the CPU
 388                 * isn't useful.
 389                 */
 390                if (i == pdata->cpu_port)
 391                        continue;
 392
 393                /*
 394                 * Set up default port names.  If present, DT port labels
 395                 * will override the default port names.
 396                 */
 397                snprintf(name, DSA_PORT_NAME_LENGTH, "%s@%d", dev->name, i);
 398
 399                ofnode_for_each_subnode(pnode, node) {
 400                        u32 reg;
 401
 402                        if (ofnode_read_u32(pnode, "reg", &reg))
 403                                continue;
 404
 405                        if (reg == i)
 406                                break;
 407                }
 408
 409                /*
 410                 * skip registration if port id not found or if the port
 411                 * is explicitly disabled in DT
 412                 */
 413                if (!ofnode_valid(pnode) || !ofnode_is_available(pnode))
 414                        continue;
 415
 416                err = device_bind_driver_to_node(dev, DSA_PORT_CHILD_DRV_NAME,
 417                                                 name, pnode, &pdev);
 418                if (pdev) {
 419                        struct dsa_port_pdata *port_pdata;
 420
 421                        port_pdata = dev_get_parent_plat(pdev);
 422                        strncpy(port_pdata->name, name, DSA_PORT_NAME_LENGTH);
 423                        pdev->name = port_pdata->name;
 424                }
 425
 426                /* try to bind all ports but keep 1st error */
 427                if (err && !first_err)
 428                        first_err = err;
 429        }
 430
 431        if (first_err)
 432                return first_err;
 433
 434        dev_dbg(dev, "DSA ports successfully bound\n");
 435
 436        return 0;
 437}
 438
 439/**
 440 * Initialize the uclass per device internal state structure (priv).
 441 * TODO: pick up references to other switch devices here, if we're cascaded.
 442 */
 443static int dsa_pre_probe(struct udevice *dev)
 444{
 445        struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
 446        struct dsa_priv *priv = dev_get_uclass_priv(dev);
 447
 448        priv->num_ports = pdata->num_ports;
 449        priv->cpu_port = pdata->cpu_port;
 450        priv->cpu_port_fixed_phy = fixed_phy_create(pdata->cpu_port_node);
 451        if (!priv->cpu_port_fixed_phy) {
 452                dev_err(dev, "Failed to register fixed-link for CPU port\n");
 453                return -ENODEV;
 454        }
 455
 456        uclass_find_device_by_ofnode(UCLASS_ETH, pdata->master_node,
 457                                     &priv->master_dev);
 458        return 0;
 459}
 460
 461UCLASS_DRIVER(dsa) = {
 462        .id = UCLASS_DSA,
 463        .name = "dsa",
 464        .post_bind = dsa_post_bind,
 465        .pre_probe = dsa_pre_probe,
 466        .per_device_auto = sizeof(struct dsa_priv),
 467        .per_device_plat_auto = sizeof(struct dsa_pdata),
 468        .per_child_plat_auto = sizeof(struct dsa_port_pdata),
 469        .flags = DM_UC_FLAG_SEQ_ALIAS,
 470};
 471