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