.. | .. |
---|
2 | 2 | /* |
---|
3 | 3 | * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name> |
---|
4 | 4 | * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> |
---|
5 | | - * Copyright (c) 2015, The Linux Foundation. All rights reserved. |
---|
| 5 | + * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. |
---|
6 | 6 | * Copyright (c) 2016 John Crispin <john@phrozen.org> |
---|
7 | 7 | */ |
---|
8 | 8 | |
---|
.. | .. |
---|
14 | 14 | #include <linux/of_platform.h> |
---|
15 | 15 | #include <linux/if_bridge.h> |
---|
16 | 16 | #include <linux/mdio.h> |
---|
| 17 | +#include <linux/phylink.h> |
---|
| 18 | +#include <linux/gpio/consumer.h> |
---|
17 | 19 | #include <linux/etherdevice.h> |
---|
18 | 20 | |
---|
19 | 21 | #include "qca8k.h" |
---|
.. | .. |
---|
406 | 408 | mutex_unlock(&priv->reg_mutex); |
---|
407 | 409 | } |
---|
408 | 410 | |
---|
| 411 | +static int |
---|
| 412 | +qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) |
---|
| 413 | +{ |
---|
| 414 | + u32 reg; |
---|
| 415 | + |
---|
| 416 | + /* Set the command and VLAN index */ |
---|
| 417 | + reg = QCA8K_VTU_FUNC1_BUSY; |
---|
| 418 | + reg |= cmd; |
---|
| 419 | + reg |= vid << QCA8K_VTU_FUNC1_VID_S; |
---|
| 420 | + |
---|
| 421 | + /* Write the function register triggering the table access */ |
---|
| 422 | + qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); |
---|
| 423 | + |
---|
| 424 | + /* wait for completion */ |
---|
| 425 | + if (qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY)) |
---|
| 426 | + return -ETIMEDOUT; |
---|
| 427 | + |
---|
| 428 | + /* Check for table full violation when adding an entry */ |
---|
| 429 | + if (cmd == QCA8K_VLAN_LOAD) { |
---|
| 430 | + reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC1); |
---|
| 431 | + if (reg & QCA8K_VTU_FUNC1_FULL) |
---|
| 432 | + return -ENOMEM; |
---|
| 433 | + } |
---|
| 434 | + |
---|
| 435 | + return 0; |
---|
| 436 | +} |
---|
| 437 | + |
---|
| 438 | +static int |
---|
| 439 | +qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) |
---|
| 440 | +{ |
---|
| 441 | + u32 reg; |
---|
| 442 | + int ret; |
---|
| 443 | + |
---|
| 444 | + /* |
---|
| 445 | + We do the right thing with VLAN 0 and treat it as untagged while |
---|
| 446 | + preserving the tag on egress. |
---|
| 447 | + */ |
---|
| 448 | + if (vid == 0) |
---|
| 449 | + return 0; |
---|
| 450 | + |
---|
| 451 | + mutex_lock(&priv->reg_mutex); |
---|
| 452 | + ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); |
---|
| 453 | + if (ret < 0) |
---|
| 454 | + goto out; |
---|
| 455 | + |
---|
| 456 | + reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC0); |
---|
| 457 | + reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; |
---|
| 458 | + reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port)); |
---|
| 459 | + if (untagged) |
---|
| 460 | + reg |= QCA8K_VTU_FUNC0_EG_MODE_UNTAG << |
---|
| 461 | + QCA8K_VTU_FUNC0_EG_MODE_S(port); |
---|
| 462 | + else |
---|
| 463 | + reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG << |
---|
| 464 | + QCA8K_VTU_FUNC0_EG_MODE_S(port); |
---|
| 465 | + |
---|
| 466 | + qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); |
---|
| 467 | + ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); |
---|
| 468 | + |
---|
| 469 | +out: |
---|
| 470 | + mutex_unlock(&priv->reg_mutex); |
---|
| 471 | + |
---|
| 472 | + return ret; |
---|
| 473 | +} |
---|
| 474 | + |
---|
| 475 | +static int |
---|
| 476 | +qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) |
---|
| 477 | +{ |
---|
| 478 | + u32 reg, mask; |
---|
| 479 | + int ret, i; |
---|
| 480 | + bool del; |
---|
| 481 | + |
---|
| 482 | + mutex_lock(&priv->reg_mutex); |
---|
| 483 | + ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); |
---|
| 484 | + if (ret < 0) |
---|
| 485 | + goto out; |
---|
| 486 | + |
---|
| 487 | + reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC0); |
---|
| 488 | + reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port)); |
---|
| 489 | + reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT << |
---|
| 490 | + QCA8K_VTU_FUNC0_EG_MODE_S(port); |
---|
| 491 | + |
---|
| 492 | + /* Check if we're the last member to be removed */ |
---|
| 493 | + del = true; |
---|
| 494 | + for (i = 0; i < QCA8K_NUM_PORTS; i++) { |
---|
| 495 | + mask = QCA8K_VTU_FUNC0_EG_MODE_NOT; |
---|
| 496 | + mask <<= QCA8K_VTU_FUNC0_EG_MODE_S(i); |
---|
| 497 | + |
---|
| 498 | + if ((reg & mask) != mask) { |
---|
| 499 | + del = false; |
---|
| 500 | + break; |
---|
| 501 | + } |
---|
| 502 | + } |
---|
| 503 | + |
---|
| 504 | + if (del) { |
---|
| 505 | + ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); |
---|
| 506 | + } else { |
---|
| 507 | + qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); |
---|
| 508 | + ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); |
---|
| 509 | + } |
---|
| 510 | + |
---|
| 511 | +out: |
---|
| 512 | + mutex_unlock(&priv->reg_mutex); |
---|
| 513 | + |
---|
| 514 | + return ret; |
---|
| 515 | +} |
---|
| 516 | + |
---|
409 | 517 | static void |
---|
410 | 518 | qca8k_mib_init(struct qca8k_priv *priv) |
---|
411 | 519 | { |
---|
.. | .. |
---|
415 | 523 | qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); |
---|
416 | 524 | qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); |
---|
417 | 525 | mutex_unlock(&priv->reg_mutex); |
---|
418 | | -} |
---|
419 | | - |
---|
420 | | -static int |
---|
421 | | -qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port, int mode) |
---|
422 | | -{ |
---|
423 | | - u32 reg; |
---|
424 | | - |
---|
425 | | - switch (port) { |
---|
426 | | - case 0: |
---|
427 | | - reg = QCA8K_REG_PORT0_PAD_CTRL; |
---|
428 | | - break; |
---|
429 | | - case 6: |
---|
430 | | - reg = QCA8K_REG_PORT6_PAD_CTRL; |
---|
431 | | - break; |
---|
432 | | - default: |
---|
433 | | - pr_err("Can't set PAD_CTRL on port %d\n", port); |
---|
434 | | - return -EINVAL; |
---|
435 | | - } |
---|
436 | | - |
---|
437 | | - /* Configure a port to be directly connected to an external |
---|
438 | | - * PHY or MAC. |
---|
439 | | - */ |
---|
440 | | - switch (mode) { |
---|
441 | | - case PHY_INTERFACE_MODE_RGMII: |
---|
442 | | - qca8k_write(priv, reg, |
---|
443 | | - QCA8K_PORT_PAD_RGMII_EN | |
---|
444 | | - QCA8K_PORT_PAD_RGMII_TX_DELAY(3) | |
---|
445 | | - QCA8K_PORT_PAD_RGMII_RX_DELAY(3)); |
---|
446 | | - |
---|
447 | | - /* According to the datasheet, RGMII delay is enabled through |
---|
448 | | - * PORT5_PAD_CTRL for all ports, rather than individual port |
---|
449 | | - * registers |
---|
450 | | - */ |
---|
451 | | - qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, |
---|
452 | | - QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); |
---|
453 | | - break; |
---|
454 | | - case PHY_INTERFACE_MODE_RGMII_ID: |
---|
455 | | - /* RGMII_ID needs internal delay. This is enabled through |
---|
456 | | - * PORT5_PAD_CTRL for all ports, rather than individual port |
---|
457 | | - * registers |
---|
458 | | - */ |
---|
459 | | - qca8k_write(priv, reg, |
---|
460 | | - QCA8K_PORT_PAD_RGMII_EN | |
---|
461 | | - QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) | |
---|
462 | | - QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY)); |
---|
463 | | - qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, |
---|
464 | | - QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); |
---|
465 | | - break; |
---|
466 | | - case PHY_INTERFACE_MODE_SGMII: |
---|
467 | | - qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); |
---|
468 | | - break; |
---|
469 | | - default: |
---|
470 | | - pr_err("xMII mode %d not supported\n", mode); |
---|
471 | | - return -EINVAL; |
---|
472 | | - } |
---|
473 | | - |
---|
474 | | - return 0; |
---|
475 | 526 | } |
---|
476 | 527 | |
---|
477 | 528 | static void |
---|
.. | .. |
---|
489 | 540 | qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); |
---|
490 | 541 | } |
---|
491 | 542 | |
---|
| 543 | +static u32 |
---|
| 544 | +qca8k_port_to_phy(int port) |
---|
| 545 | +{ |
---|
| 546 | + /* From Andrew Lunn: |
---|
| 547 | + * Port 0 has no internal phy. |
---|
| 548 | + * Port 1 has an internal PHY at MDIO address 0. |
---|
| 549 | + * Port 2 has an internal PHY at MDIO address 1. |
---|
| 550 | + * ... |
---|
| 551 | + * Port 5 has an internal PHY at MDIO address 4. |
---|
| 552 | + * Port 6 has no internal PHY. |
---|
| 553 | + */ |
---|
| 554 | + |
---|
| 555 | + return port - 1; |
---|
| 556 | +} |
---|
| 557 | + |
---|
| 558 | +static int |
---|
| 559 | +qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data) |
---|
| 560 | +{ |
---|
| 561 | + u32 phy, val; |
---|
| 562 | + |
---|
| 563 | + if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) |
---|
| 564 | + return -EINVAL; |
---|
| 565 | + |
---|
| 566 | + /* callee is responsible for not passing bad ports, |
---|
| 567 | + * but we still would like to make spills impossible. |
---|
| 568 | + */ |
---|
| 569 | + phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR; |
---|
| 570 | + val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | |
---|
| 571 | + QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | |
---|
| 572 | + QCA8K_MDIO_MASTER_REG_ADDR(regnum) | |
---|
| 573 | + QCA8K_MDIO_MASTER_DATA(data); |
---|
| 574 | + |
---|
| 575 | + qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val); |
---|
| 576 | + |
---|
| 577 | + return qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL, |
---|
| 578 | + QCA8K_MDIO_MASTER_BUSY); |
---|
| 579 | +} |
---|
| 580 | + |
---|
| 581 | +static int |
---|
| 582 | +qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum) |
---|
| 583 | +{ |
---|
| 584 | + u32 phy, val; |
---|
| 585 | + |
---|
| 586 | + if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) |
---|
| 587 | + return -EINVAL; |
---|
| 588 | + |
---|
| 589 | + /* callee is responsible for not passing bad ports, |
---|
| 590 | + * but we still would like to make spills impossible. |
---|
| 591 | + */ |
---|
| 592 | + phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR; |
---|
| 593 | + val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | |
---|
| 594 | + QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | |
---|
| 595 | + QCA8K_MDIO_MASTER_REG_ADDR(regnum); |
---|
| 596 | + |
---|
| 597 | + qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val); |
---|
| 598 | + |
---|
| 599 | + if (qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL, |
---|
| 600 | + QCA8K_MDIO_MASTER_BUSY)) |
---|
| 601 | + return -ETIMEDOUT; |
---|
| 602 | + |
---|
| 603 | + val = (qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL) & |
---|
| 604 | + QCA8K_MDIO_MASTER_DATA_MASK); |
---|
| 605 | + |
---|
| 606 | + return val; |
---|
| 607 | +} |
---|
| 608 | + |
---|
| 609 | +static int |
---|
| 610 | +qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data) |
---|
| 611 | +{ |
---|
| 612 | + struct qca8k_priv *priv = ds->priv; |
---|
| 613 | + |
---|
| 614 | + return qca8k_mdio_write(priv, port, regnum, data); |
---|
| 615 | +} |
---|
| 616 | + |
---|
| 617 | +static int |
---|
| 618 | +qca8k_phy_read(struct dsa_switch *ds, int port, int regnum) |
---|
| 619 | +{ |
---|
| 620 | + struct qca8k_priv *priv = ds->priv; |
---|
| 621 | + int ret; |
---|
| 622 | + |
---|
| 623 | + ret = qca8k_mdio_read(priv, port, regnum); |
---|
| 624 | + |
---|
| 625 | + if (ret < 0) |
---|
| 626 | + return 0xffff; |
---|
| 627 | + |
---|
| 628 | + return ret; |
---|
| 629 | +} |
---|
| 630 | + |
---|
| 631 | +static int |
---|
| 632 | +qca8k_setup_mdio_bus(struct qca8k_priv *priv) |
---|
| 633 | +{ |
---|
| 634 | + u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; |
---|
| 635 | + struct device_node *ports, *port; |
---|
| 636 | + int err; |
---|
| 637 | + |
---|
| 638 | + ports = of_get_child_by_name(priv->dev->of_node, "ports"); |
---|
| 639 | + if (!ports) |
---|
| 640 | + return -EINVAL; |
---|
| 641 | + |
---|
| 642 | + for_each_available_child_of_node(ports, port) { |
---|
| 643 | + err = of_property_read_u32(port, "reg", ®); |
---|
| 644 | + if (err) { |
---|
| 645 | + of_node_put(port); |
---|
| 646 | + of_node_put(ports); |
---|
| 647 | + return err; |
---|
| 648 | + } |
---|
| 649 | + |
---|
| 650 | + if (!dsa_is_user_port(priv->ds, reg)) |
---|
| 651 | + continue; |
---|
| 652 | + |
---|
| 653 | + if (of_property_read_bool(port, "phy-handle")) |
---|
| 654 | + external_mdio_mask |= BIT(reg); |
---|
| 655 | + else |
---|
| 656 | + internal_mdio_mask |= BIT(reg); |
---|
| 657 | + } |
---|
| 658 | + |
---|
| 659 | + of_node_put(ports); |
---|
| 660 | + if (!external_mdio_mask && !internal_mdio_mask) { |
---|
| 661 | + dev_err(priv->dev, "no PHYs are defined.\n"); |
---|
| 662 | + return -EINVAL; |
---|
| 663 | + } |
---|
| 664 | + |
---|
| 665 | + /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through |
---|
| 666 | + * the MDIO_MASTER register also _disconnects_ the external MDC |
---|
| 667 | + * passthrough to the internal PHYs. It's not possible to use both |
---|
| 668 | + * configurations at the same time! |
---|
| 669 | + * |
---|
| 670 | + * Because this came up during the review process: |
---|
| 671 | + * If the external mdio-bus driver is capable magically disabling |
---|
| 672 | + * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's |
---|
| 673 | + * accessors for the time being, it would be possible to pull this |
---|
| 674 | + * off. |
---|
| 675 | + */ |
---|
| 676 | + if (!!external_mdio_mask && !!internal_mdio_mask) { |
---|
| 677 | + dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); |
---|
| 678 | + return -EINVAL; |
---|
| 679 | + } |
---|
| 680 | + |
---|
| 681 | + if (external_mdio_mask) { |
---|
| 682 | + /* Make sure to disable the internal mdio bus in cases |
---|
| 683 | + * a dt-overlay and driver reload changed the configuration |
---|
| 684 | + */ |
---|
| 685 | + |
---|
| 686 | + qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL, |
---|
| 687 | + QCA8K_MDIO_MASTER_EN); |
---|
| 688 | + return 0; |
---|
| 689 | + } |
---|
| 690 | + |
---|
| 691 | + priv->ops.phy_read = qca8k_phy_read; |
---|
| 692 | + priv->ops.phy_write = qca8k_phy_write; |
---|
| 693 | + return 0; |
---|
| 694 | +} |
---|
| 695 | + |
---|
492 | 696 | static int |
---|
493 | 697 | qca8k_setup(struct dsa_switch *ds) |
---|
494 | 698 | { |
---|
495 | 699 | struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; |
---|
496 | | - int ret, i, phy_mode = -1; |
---|
497 | | - u32 mask; |
---|
| 700 | + int ret, i; |
---|
498 | 701 | |
---|
499 | 702 | /* Make sure that port 0 is the cpu port */ |
---|
500 | 703 | if (!dsa_is_cpu_port(ds, 0)) { |
---|
.. | .. |
---|
510 | 713 | if (IS_ERR(priv->regmap)) |
---|
511 | 714 | pr_warn("regmap initialization failed"); |
---|
512 | 715 | |
---|
513 | | - /* Initialize CPU port pad mode (xMII type, delays...) */ |
---|
514 | | - phy_mode = of_get_phy_mode(ds->ports[QCA8K_CPU_PORT].dn); |
---|
515 | | - if (phy_mode < 0) { |
---|
516 | | - pr_err("Can't find phy-mode for master device\n"); |
---|
517 | | - return phy_mode; |
---|
518 | | - } |
---|
519 | | - ret = qca8k_set_pad_ctrl(priv, QCA8K_CPU_PORT, phy_mode); |
---|
520 | | - if (ret < 0) |
---|
| 716 | + ret = qca8k_setup_mdio_bus(priv); |
---|
| 717 | + if (ret) |
---|
521 | 718 | return ret; |
---|
522 | 719 | |
---|
523 | | - /* Enable CPU Port, force it to maximum bandwidth and full-duplex */ |
---|
524 | | - mask = QCA8K_PORT_STATUS_SPEED_1000 | QCA8K_PORT_STATUS_TXFLOW | |
---|
525 | | - QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_DUPLEX; |
---|
526 | | - qca8k_write(priv, QCA8K_REG_PORT_STATUS(QCA8K_CPU_PORT), mask); |
---|
| 720 | + /* Enable CPU Port */ |
---|
527 | 721 | qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, |
---|
528 | 722 | QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); |
---|
529 | | - qca8k_port_set_status(priv, QCA8K_CPU_PORT, 1); |
---|
530 | | - priv->port_sts[QCA8K_CPU_PORT].enabled = 1; |
---|
531 | 723 | |
---|
532 | 724 | /* Enable MIB counters */ |
---|
533 | 725 | qca8k_mib_init(priv); |
---|
.. | .. |
---|
542 | 734 | qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), |
---|
543 | 735 | QCA8K_PORT_LOOKUP_MEMBER, 0); |
---|
544 | 736 | |
---|
545 | | - /* Disable MAC by default on all user ports */ |
---|
| 737 | + /* Disable MAC by default on all ports */ |
---|
546 | 738 | for (i = 1; i < QCA8K_NUM_PORTS; i++) |
---|
547 | | - if (dsa_is_user_port(ds, i)) |
---|
548 | | - qca8k_port_set_status(priv, i, 0); |
---|
| 739 | + qca8k_port_set_status(priv, i, 0); |
---|
549 | 740 | |
---|
550 | 741 | /* Forward all unknown frames to CPU port for Linux processing */ |
---|
551 | 742 | qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, |
---|
.. | .. |
---|
562 | 753 | QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); |
---|
563 | 754 | } |
---|
564 | 755 | |
---|
565 | | - /* Invividual user ports get connected to CPU port only */ |
---|
| 756 | + /* Individual user ports get connected to CPU port only */ |
---|
566 | 757 | if (dsa_is_user_port(ds, i)) { |
---|
567 | 758 | int shift = 16 * (i % 2); |
---|
568 | 759 | |
---|
.. | .. |
---|
578 | 769 | * default egress vid |
---|
579 | 770 | */ |
---|
580 | 771 | qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), |
---|
581 | | - 0xffff << shift, 1 << shift); |
---|
| 772 | + 0xfff << shift, |
---|
| 773 | + QCA8K_PORT_VID_DEF << shift); |
---|
582 | 774 | qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), |
---|
583 | | - QCA8K_PORT_VLAN_CVID(1) | |
---|
584 | | - QCA8K_PORT_VLAN_SVID(1)); |
---|
| 775 | + QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | |
---|
| 776 | + QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); |
---|
585 | 777 | } |
---|
586 | 778 | } |
---|
587 | 779 | |
---|
| 780 | + /* Setup our port MTUs to match power on defaults */ |
---|
| 781 | + for (i = 0; i < QCA8K_NUM_PORTS; i++) |
---|
| 782 | + priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; |
---|
| 783 | + qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); |
---|
| 784 | + |
---|
588 | 785 | /* Flush the FDB table */ |
---|
589 | 786 | qca8k_fdb_flush(priv); |
---|
| 787 | + |
---|
| 788 | + /* We don't have interrupts for link changes, so we need to poll */ |
---|
| 789 | + ds->pcs_poll = true; |
---|
590 | 790 | |
---|
591 | 791 | return 0; |
---|
592 | 792 | } |
---|
593 | 793 | |
---|
594 | 794 | static void |
---|
595 | | -qca8k_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phy) |
---|
| 795 | +qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, |
---|
| 796 | + const struct phylink_link_state *state) |
---|
| 797 | +{ |
---|
| 798 | + struct qca8k_priv *priv = ds->priv; |
---|
| 799 | + u32 reg, val; |
---|
| 800 | + |
---|
| 801 | + switch (port) { |
---|
| 802 | + case 0: /* 1st CPU port */ |
---|
| 803 | + if (state->interface != PHY_INTERFACE_MODE_RGMII && |
---|
| 804 | + state->interface != PHY_INTERFACE_MODE_RGMII_ID && |
---|
| 805 | + state->interface != PHY_INTERFACE_MODE_SGMII) |
---|
| 806 | + return; |
---|
| 807 | + |
---|
| 808 | + reg = QCA8K_REG_PORT0_PAD_CTRL; |
---|
| 809 | + break; |
---|
| 810 | + case 1: |
---|
| 811 | + case 2: |
---|
| 812 | + case 3: |
---|
| 813 | + case 4: |
---|
| 814 | + case 5: |
---|
| 815 | + /* Internal PHY, nothing to do */ |
---|
| 816 | + return; |
---|
| 817 | + case 6: /* 2nd CPU port / external PHY */ |
---|
| 818 | + if (state->interface != PHY_INTERFACE_MODE_RGMII && |
---|
| 819 | + state->interface != PHY_INTERFACE_MODE_RGMII_ID && |
---|
| 820 | + state->interface != PHY_INTERFACE_MODE_SGMII && |
---|
| 821 | + state->interface != PHY_INTERFACE_MODE_1000BASEX) |
---|
| 822 | + return; |
---|
| 823 | + |
---|
| 824 | + reg = QCA8K_REG_PORT6_PAD_CTRL; |
---|
| 825 | + break; |
---|
| 826 | + default: |
---|
| 827 | + dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); |
---|
| 828 | + return; |
---|
| 829 | + } |
---|
| 830 | + |
---|
| 831 | + if (port != 6 && phylink_autoneg_inband(mode)) { |
---|
| 832 | + dev_err(ds->dev, "%s: in-band negotiation unsupported\n", |
---|
| 833 | + __func__); |
---|
| 834 | + return; |
---|
| 835 | + } |
---|
| 836 | + |
---|
| 837 | + switch (state->interface) { |
---|
| 838 | + case PHY_INTERFACE_MODE_RGMII: |
---|
| 839 | + /* RGMII mode means no delay so don't enable the delay */ |
---|
| 840 | + qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); |
---|
| 841 | + break; |
---|
| 842 | + case PHY_INTERFACE_MODE_RGMII_ID: |
---|
| 843 | + /* RGMII_ID needs internal delay. This is enabled through |
---|
| 844 | + * PORT5_PAD_CTRL for all ports, rather than individual port |
---|
| 845 | + * registers |
---|
| 846 | + */ |
---|
| 847 | + qca8k_write(priv, reg, |
---|
| 848 | + QCA8K_PORT_PAD_RGMII_EN | |
---|
| 849 | + QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) | |
---|
| 850 | + QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY)); |
---|
| 851 | + qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, |
---|
| 852 | + QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); |
---|
| 853 | + break; |
---|
| 854 | + case PHY_INTERFACE_MODE_SGMII: |
---|
| 855 | + case PHY_INTERFACE_MODE_1000BASEX: |
---|
| 856 | + /* Enable SGMII on the port */ |
---|
| 857 | + qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); |
---|
| 858 | + |
---|
| 859 | + /* Enable/disable SerDes auto-negotiation as necessary */ |
---|
| 860 | + val = qca8k_read(priv, QCA8K_REG_PWS); |
---|
| 861 | + if (phylink_autoneg_inband(mode)) |
---|
| 862 | + val &= ~QCA8K_PWS_SERDES_AEN_DIS; |
---|
| 863 | + else |
---|
| 864 | + val |= QCA8K_PWS_SERDES_AEN_DIS; |
---|
| 865 | + qca8k_write(priv, QCA8K_REG_PWS, val); |
---|
| 866 | + |
---|
| 867 | + /* Configure the SGMII parameters */ |
---|
| 868 | + val = qca8k_read(priv, QCA8K_REG_SGMII_CTRL); |
---|
| 869 | + |
---|
| 870 | + val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | |
---|
| 871 | + QCA8K_SGMII_EN_TX | QCA8K_SGMII_EN_SD; |
---|
| 872 | + |
---|
| 873 | + if (dsa_is_cpu_port(ds, port)) { |
---|
| 874 | + /* CPU port, we're talking to the CPU MAC, be a PHY */ |
---|
| 875 | + val &= ~QCA8K_SGMII_MODE_CTRL_MASK; |
---|
| 876 | + val |= QCA8K_SGMII_MODE_CTRL_PHY; |
---|
| 877 | + } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { |
---|
| 878 | + val &= ~QCA8K_SGMII_MODE_CTRL_MASK; |
---|
| 879 | + val |= QCA8K_SGMII_MODE_CTRL_MAC; |
---|
| 880 | + } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { |
---|
| 881 | + val &= ~QCA8K_SGMII_MODE_CTRL_MASK; |
---|
| 882 | + val |= QCA8K_SGMII_MODE_CTRL_BASEX; |
---|
| 883 | + } |
---|
| 884 | + |
---|
| 885 | + qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); |
---|
| 886 | + break; |
---|
| 887 | + default: |
---|
| 888 | + dev_err(ds->dev, "xMII mode %s not supported for port %d\n", |
---|
| 889 | + phy_modes(state->interface), port); |
---|
| 890 | + return; |
---|
| 891 | + } |
---|
| 892 | +} |
---|
| 893 | + |
---|
| 894 | +static void |
---|
| 895 | +qca8k_phylink_validate(struct dsa_switch *ds, int port, |
---|
| 896 | + unsigned long *supported, |
---|
| 897 | + struct phylink_link_state *state) |
---|
| 898 | +{ |
---|
| 899 | + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; |
---|
| 900 | + |
---|
| 901 | + switch (port) { |
---|
| 902 | + case 0: /* 1st CPU port */ |
---|
| 903 | + if (state->interface != PHY_INTERFACE_MODE_NA && |
---|
| 904 | + state->interface != PHY_INTERFACE_MODE_RGMII && |
---|
| 905 | + state->interface != PHY_INTERFACE_MODE_RGMII_ID && |
---|
| 906 | + state->interface != PHY_INTERFACE_MODE_SGMII) |
---|
| 907 | + goto unsupported; |
---|
| 908 | + break; |
---|
| 909 | + case 1: |
---|
| 910 | + case 2: |
---|
| 911 | + case 3: |
---|
| 912 | + case 4: |
---|
| 913 | + case 5: |
---|
| 914 | + /* Internal PHY */ |
---|
| 915 | + if (state->interface != PHY_INTERFACE_MODE_NA && |
---|
| 916 | + state->interface != PHY_INTERFACE_MODE_GMII) |
---|
| 917 | + goto unsupported; |
---|
| 918 | + break; |
---|
| 919 | + case 6: /* 2nd CPU port / external PHY */ |
---|
| 920 | + if (state->interface != PHY_INTERFACE_MODE_NA && |
---|
| 921 | + state->interface != PHY_INTERFACE_MODE_RGMII && |
---|
| 922 | + state->interface != PHY_INTERFACE_MODE_RGMII_ID && |
---|
| 923 | + state->interface != PHY_INTERFACE_MODE_SGMII && |
---|
| 924 | + state->interface != PHY_INTERFACE_MODE_1000BASEX) |
---|
| 925 | + goto unsupported; |
---|
| 926 | + break; |
---|
| 927 | + default: |
---|
| 928 | +unsupported: |
---|
| 929 | + linkmode_zero(supported); |
---|
| 930 | + return; |
---|
| 931 | + } |
---|
| 932 | + |
---|
| 933 | + phylink_set_port_modes(mask); |
---|
| 934 | + phylink_set(mask, Autoneg); |
---|
| 935 | + |
---|
| 936 | + phylink_set(mask, 1000baseT_Full); |
---|
| 937 | + phylink_set(mask, 10baseT_Half); |
---|
| 938 | + phylink_set(mask, 10baseT_Full); |
---|
| 939 | + phylink_set(mask, 100baseT_Half); |
---|
| 940 | + phylink_set(mask, 100baseT_Full); |
---|
| 941 | + |
---|
| 942 | + if (state->interface == PHY_INTERFACE_MODE_1000BASEX) |
---|
| 943 | + phylink_set(mask, 1000baseX_Full); |
---|
| 944 | + |
---|
| 945 | + phylink_set(mask, Pause); |
---|
| 946 | + phylink_set(mask, Asym_Pause); |
---|
| 947 | + |
---|
| 948 | + linkmode_and(supported, supported, mask); |
---|
| 949 | + linkmode_and(state->advertising, state->advertising, mask); |
---|
| 950 | +} |
---|
| 951 | + |
---|
| 952 | +static int |
---|
| 953 | +qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, |
---|
| 954 | + struct phylink_link_state *state) |
---|
596 | 955 | { |
---|
597 | 956 | struct qca8k_priv *priv = ds->priv; |
---|
598 | 957 | u32 reg; |
---|
599 | 958 | |
---|
600 | | - /* Force fixed-link setting for CPU port, skip others. */ |
---|
601 | | - if (!phy_is_pseudo_fixed_link(phy)) |
---|
602 | | - return; |
---|
| 959 | + reg = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port)); |
---|
603 | 960 | |
---|
604 | | - /* Set port speed */ |
---|
605 | | - switch (phy->speed) { |
---|
606 | | - case 10: |
---|
607 | | - reg = QCA8K_PORT_STATUS_SPEED_10; |
---|
| 961 | + state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); |
---|
| 962 | + state->an_complete = state->link; |
---|
| 963 | + state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); |
---|
| 964 | + state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : |
---|
| 965 | + DUPLEX_HALF; |
---|
| 966 | + |
---|
| 967 | + switch (reg & QCA8K_PORT_STATUS_SPEED) { |
---|
| 968 | + case QCA8K_PORT_STATUS_SPEED_10: |
---|
| 969 | + state->speed = SPEED_10; |
---|
608 | 970 | break; |
---|
609 | | - case 100: |
---|
610 | | - reg = QCA8K_PORT_STATUS_SPEED_100; |
---|
| 971 | + case QCA8K_PORT_STATUS_SPEED_100: |
---|
| 972 | + state->speed = SPEED_100; |
---|
611 | 973 | break; |
---|
612 | | - case 1000: |
---|
613 | | - reg = QCA8K_PORT_STATUS_SPEED_1000; |
---|
| 974 | + case QCA8K_PORT_STATUS_SPEED_1000: |
---|
| 975 | + state->speed = SPEED_1000; |
---|
614 | 976 | break; |
---|
615 | 977 | default: |
---|
616 | | - dev_dbg(priv->dev, "port%d link speed %dMbps not supported.\n", |
---|
617 | | - port, phy->speed); |
---|
618 | | - return; |
---|
| 978 | + state->speed = SPEED_UNKNOWN; |
---|
| 979 | + break; |
---|
619 | 980 | } |
---|
620 | 981 | |
---|
621 | | - /* Set duplex mode */ |
---|
622 | | - if (phy->duplex == DUPLEX_FULL) |
---|
623 | | - reg |= QCA8K_PORT_STATUS_DUPLEX; |
---|
| 982 | + state->pause = MLO_PAUSE_NONE; |
---|
| 983 | + if (reg & QCA8K_PORT_STATUS_RXFLOW) |
---|
| 984 | + state->pause |= MLO_PAUSE_RX; |
---|
| 985 | + if (reg & QCA8K_PORT_STATUS_TXFLOW) |
---|
| 986 | + state->pause |= MLO_PAUSE_TX; |
---|
624 | 987 | |
---|
625 | | - /* Force flow control */ |
---|
626 | | - if (dsa_is_cpu_port(ds, port)) |
---|
627 | | - reg |= QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_TXFLOW; |
---|
| 988 | + return 1; |
---|
| 989 | +} |
---|
628 | 990 | |
---|
629 | | - /* Force link down before changing MAC options */ |
---|
| 991 | +static void |
---|
| 992 | +qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, |
---|
| 993 | + phy_interface_t interface) |
---|
| 994 | +{ |
---|
| 995 | + struct qca8k_priv *priv = ds->priv; |
---|
| 996 | + |
---|
630 | 997 | qca8k_port_set_status(priv, port, 0); |
---|
| 998 | +} |
---|
| 999 | + |
---|
| 1000 | +static void |
---|
| 1001 | +qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, |
---|
| 1002 | + phy_interface_t interface, struct phy_device *phydev, |
---|
| 1003 | + int speed, int duplex, bool tx_pause, bool rx_pause) |
---|
| 1004 | +{ |
---|
| 1005 | + struct qca8k_priv *priv = ds->priv; |
---|
| 1006 | + u32 reg; |
---|
| 1007 | + |
---|
| 1008 | + if (phylink_autoneg_inband(mode)) { |
---|
| 1009 | + reg = QCA8K_PORT_STATUS_LINK_AUTO; |
---|
| 1010 | + } else { |
---|
| 1011 | + switch (speed) { |
---|
| 1012 | + case SPEED_10: |
---|
| 1013 | + reg = QCA8K_PORT_STATUS_SPEED_10; |
---|
| 1014 | + break; |
---|
| 1015 | + case SPEED_100: |
---|
| 1016 | + reg = QCA8K_PORT_STATUS_SPEED_100; |
---|
| 1017 | + break; |
---|
| 1018 | + case SPEED_1000: |
---|
| 1019 | + reg = QCA8K_PORT_STATUS_SPEED_1000; |
---|
| 1020 | + break; |
---|
| 1021 | + default: |
---|
| 1022 | + reg = QCA8K_PORT_STATUS_LINK_AUTO; |
---|
| 1023 | + break; |
---|
| 1024 | + } |
---|
| 1025 | + |
---|
| 1026 | + if (duplex == DUPLEX_FULL) |
---|
| 1027 | + reg |= QCA8K_PORT_STATUS_DUPLEX; |
---|
| 1028 | + |
---|
| 1029 | + if (rx_pause || dsa_is_cpu_port(ds, port)) |
---|
| 1030 | + reg |= QCA8K_PORT_STATUS_RXFLOW; |
---|
| 1031 | + |
---|
| 1032 | + if (tx_pause || dsa_is_cpu_port(ds, port)) |
---|
| 1033 | + reg |= QCA8K_PORT_STATUS_TXFLOW; |
---|
| 1034 | + } |
---|
| 1035 | + |
---|
| 1036 | + reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; |
---|
| 1037 | + |
---|
631 | 1038 | qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); |
---|
632 | | - qca8k_port_set_status(priv, port, 1); |
---|
633 | 1039 | } |
---|
634 | 1040 | |
---|
635 | 1041 | static void |
---|
.. | .. |
---|
789 | 1195 | qca8k_port_set_status(priv, port, 1); |
---|
790 | 1196 | priv->port_sts[port].enabled = 1; |
---|
791 | 1197 | |
---|
| 1198 | + if (dsa_is_user_port(ds, port)) |
---|
| 1199 | + phy_support_asym_pause(phy); |
---|
| 1200 | + |
---|
792 | 1201 | return 0; |
---|
793 | 1202 | } |
---|
794 | 1203 | |
---|
795 | 1204 | static void |
---|
796 | | -qca8k_port_disable(struct dsa_switch *ds, int port, |
---|
797 | | - struct phy_device *phy) |
---|
| 1205 | +qca8k_port_disable(struct dsa_switch *ds, int port) |
---|
798 | 1206 | { |
---|
799 | 1207 | struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; |
---|
800 | 1208 | |
---|
.. | .. |
---|
803 | 1211 | } |
---|
804 | 1212 | |
---|
805 | 1213 | static int |
---|
| 1214 | +qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) |
---|
| 1215 | +{ |
---|
| 1216 | + struct qca8k_priv *priv = ds->priv; |
---|
| 1217 | + int i, mtu = 0; |
---|
| 1218 | + |
---|
| 1219 | + priv->port_mtu[port] = new_mtu; |
---|
| 1220 | + |
---|
| 1221 | + for (i = 0; i < QCA8K_NUM_PORTS; i++) |
---|
| 1222 | + if (priv->port_mtu[i] > mtu) |
---|
| 1223 | + mtu = priv->port_mtu[i]; |
---|
| 1224 | + |
---|
| 1225 | + /* Include L2 header / FCS length */ |
---|
| 1226 | + qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN); |
---|
| 1227 | + |
---|
| 1228 | + return 0; |
---|
| 1229 | +} |
---|
| 1230 | + |
---|
| 1231 | +static int |
---|
| 1232 | +qca8k_port_max_mtu(struct dsa_switch *ds, int port) |
---|
| 1233 | +{ |
---|
| 1234 | + return QCA8K_MAX_MTU; |
---|
| 1235 | +} |
---|
| 1236 | + |
---|
| 1237 | +static int |
---|
806 | 1238 | qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, |
---|
807 | 1239 | u16 port_mask, u16 vid) |
---|
808 | 1240 | { |
---|
809 | 1241 | /* Set the vid to the port vlan id if no vid is set */ |
---|
810 | 1242 | if (!vid) |
---|
811 | | - vid = 1; |
---|
| 1243 | + vid = QCA8K_PORT_VID_DEF; |
---|
812 | 1244 | |
---|
813 | 1245 | return qca8k_fdb_add(priv, addr, port_mask, vid, |
---|
814 | 1246 | QCA8K_ATU_STATUS_STATIC); |
---|
.. | .. |
---|
832 | 1264 | u16 port_mask = BIT(port); |
---|
833 | 1265 | |
---|
834 | 1266 | if (!vid) |
---|
835 | | - vid = 1; |
---|
| 1267 | + vid = QCA8K_PORT_VID_DEF; |
---|
836 | 1268 | |
---|
837 | 1269 | return qca8k_fdb_del(priv, addr, port_mask, vid); |
---|
838 | 1270 | } |
---|
.. | .. |
---|
861 | 1293 | return 0; |
---|
862 | 1294 | } |
---|
863 | 1295 | |
---|
| 1296 | +static int |
---|
| 1297 | +qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, |
---|
| 1298 | + struct switchdev_trans *trans) |
---|
| 1299 | +{ |
---|
| 1300 | + struct qca8k_priv *priv = ds->priv; |
---|
| 1301 | + |
---|
| 1302 | + if (switchdev_trans_ph_prepare(trans)) |
---|
| 1303 | + return 0; |
---|
| 1304 | + |
---|
| 1305 | + if (vlan_filtering) { |
---|
| 1306 | + qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), |
---|
| 1307 | + QCA8K_PORT_LOOKUP_VLAN_MODE, |
---|
| 1308 | + QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); |
---|
| 1309 | + } else { |
---|
| 1310 | + qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), |
---|
| 1311 | + QCA8K_PORT_LOOKUP_VLAN_MODE, |
---|
| 1312 | + QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); |
---|
| 1313 | + } |
---|
| 1314 | + |
---|
| 1315 | + return 0; |
---|
| 1316 | +} |
---|
| 1317 | + |
---|
| 1318 | +static int |
---|
| 1319 | +qca8k_port_vlan_prepare(struct dsa_switch *ds, int port, |
---|
| 1320 | + const struct switchdev_obj_port_vlan *vlan) |
---|
| 1321 | +{ |
---|
| 1322 | + return 0; |
---|
| 1323 | +} |
---|
| 1324 | + |
---|
| 1325 | +static void |
---|
| 1326 | +qca8k_port_vlan_add(struct dsa_switch *ds, int port, |
---|
| 1327 | + const struct switchdev_obj_port_vlan *vlan) |
---|
| 1328 | +{ |
---|
| 1329 | + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; |
---|
| 1330 | + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; |
---|
| 1331 | + struct qca8k_priv *priv = ds->priv; |
---|
| 1332 | + int ret = 0; |
---|
| 1333 | + u16 vid; |
---|
| 1334 | + |
---|
| 1335 | + for (vid = vlan->vid_begin; vid <= vlan->vid_end && !ret; ++vid) |
---|
| 1336 | + ret = qca8k_vlan_add(priv, port, vid, untagged); |
---|
| 1337 | + |
---|
| 1338 | + if (ret) |
---|
| 1339 | + dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); |
---|
| 1340 | + |
---|
| 1341 | + if (pvid) { |
---|
| 1342 | + int shift = 16 * (port % 2); |
---|
| 1343 | + |
---|
| 1344 | + qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), |
---|
| 1345 | + 0xfff << shift, |
---|
| 1346 | + vlan->vid_end << shift); |
---|
| 1347 | + qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), |
---|
| 1348 | + QCA8K_PORT_VLAN_CVID(vlan->vid_end) | |
---|
| 1349 | + QCA8K_PORT_VLAN_SVID(vlan->vid_end)); |
---|
| 1350 | + } |
---|
| 1351 | +} |
---|
| 1352 | + |
---|
| 1353 | +static int |
---|
| 1354 | +qca8k_port_vlan_del(struct dsa_switch *ds, int port, |
---|
| 1355 | + const struct switchdev_obj_port_vlan *vlan) |
---|
| 1356 | +{ |
---|
| 1357 | + struct qca8k_priv *priv = ds->priv; |
---|
| 1358 | + int ret = 0; |
---|
| 1359 | + u16 vid; |
---|
| 1360 | + |
---|
| 1361 | + for (vid = vlan->vid_begin; vid <= vlan->vid_end && !ret; ++vid) |
---|
| 1362 | + ret = qca8k_vlan_del(priv, port, vid); |
---|
| 1363 | + |
---|
| 1364 | + if (ret) |
---|
| 1365 | + dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); |
---|
| 1366 | + |
---|
| 1367 | + return ret; |
---|
| 1368 | +} |
---|
| 1369 | + |
---|
864 | 1370 | static enum dsa_tag_protocol |
---|
865 | | -qca8k_get_tag_protocol(struct dsa_switch *ds, int port) |
---|
| 1371 | +qca8k_get_tag_protocol(struct dsa_switch *ds, int port, |
---|
| 1372 | + enum dsa_tag_protocol mp) |
---|
866 | 1373 | { |
---|
867 | 1374 | return DSA_TAG_PROTO_QCA; |
---|
868 | 1375 | } |
---|
.. | .. |
---|
870 | 1377 | static const struct dsa_switch_ops qca8k_switch_ops = { |
---|
871 | 1378 | .get_tag_protocol = qca8k_get_tag_protocol, |
---|
872 | 1379 | .setup = qca8k_setup, |
---|
873 | | - .adjust_link = qca8k_adjust_link, |
---|
874 | 1380 | .get_strings = qca8k_get_strings, |
---|
875 | 1381 | .get_ethtool_stats = qca8k_get_ethtool_stats, |
---|
876 | 1382 | .get_sset_count = qca8k_get_sset_count, |
---|
.. | .. |
---|
878 | 1384 | .set_mac_eee = qca8k_set_mac_eee, |
---|
879 | 1385 | .port_enable = qca8k_port_enable, |
---|
880 | 1386 | .port_disable = qca8k_port_disable, |
---|
| 1387 | + .port_change_mtu = qca8k_port_change_mtu, |
---|
| 1388 | + .port_max_mtu = qca8k_port_max_mtu, |
---|
881 | 1389 | .port_stp_state_set = qca8k_port_stp_state_set, |
---|
882 | 1390 | .port_bridge_join = qca8k_port_bridge_join, |
---|
883 | 1391 | .port_bridge_leave = qca8k_port_bridge_leave, |
---|
884 | 1392 | .port_fdb_add = qca8k_port_fdb_add, |
---|
885 | 1393 | .port_fdb_del = qca8k_port_fdb_del, |
---|
886 | 1394 | .port_fdb_dump = qca8k_port_fdb_dump, |
---|
| 1395 | + .port_vlan_filtering = qca8k_port_vlan_filtering, |
---|
| 1396 | + .port_vlan_prepare = qca8k_port_vlan_prepare, |
---|
| 1397 | + .port_vlan_add = qca8k_port_vlan_add, |
---|
| 1398 | + .port_vlan_del = qca8k_port_vlan_del, |
---|
| 1399 | + .phylink_validate = qca8k_phylink_validate, |
---|
| 1400 | + .phylink_mac_link_state = qca8k_phylink_mac_link_state, |
---|
| 1401 | + .phylink_mac_config = qca8k_phylink_mac_config, |
---|
| 1402 | + .phylink_mac_link_down = qca8k_phylink_mac_link_down, |
---|
| 1403 | + .phylink_mac_link_up = qca8k_phylink_mac_link_up, |
---|
887 | 1404 | }; |
---|
888 | 1405 | |
---|
889 | 1406 | static int |
---|
.. | .. |
---|
902 | 1419 | priv->bus = mdiodev->bus; |
---|
903 | 1420 | priv->dev = &mdiodev->dev; |
---|
904 | 1421 | |
---|
| 1422 | + priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", |
---|
| 1423 | + GPIOD_ASIS); |
---|
| 1424 | + if (IS_ERR(priv->reset_gpio)) |
---|
| 1425 | + return PTR_ERR(priv->reset_gpio); |
---|
| 1426 | + |
---|
| 1427 | + if (priv->reset_gpio) { |
---|
| 1428 | + gpiod_set_value_cansleep(priv->reset_gpio, 1); |
---|
| 1429 | + /* The active low duration must be greater than 10 ms |
---|
| 1430 | + * and checkpatch.pl wants 20 ms. |
---|
| 1431 | + */ |
---|
| 1432 | + msleep(20); |
---|
| 1433 | + gpiod_set_value_cansleep(priv->reset_gpio, 0); |
---|
| 1434 | + } |
---|
| 1435 | + |
---|
905 | 1436 | /* read the switches ID register */ |
---|
906 | 1437 | id = qca8k_read(priv, QCA8K_REG_MASK_CTRL); |
---|
907 | 1438 | id >>= QCA8K_MASK_CTRL_ID_S; |
---|
.. | .. |
---|
909 | 1440 | if (id != QCA8K_ID_QCA8337) |
---|
910 | 1441 | return -ENODEV; |
---|
911 | 1442 | |
---|
912 | | - priv->ds = dsa_switch_alloc(&mdiodev->dev, QCA8K_NUM_PORTS); |
---|
| 1443 | + priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); |
---|
913 | 1444 | if (!priv->ds) |
---|
914 | 1445 | return -ENOMEM; |
---|
915 | 1446 | |
---|
| 1447 | + priv->ds->dev = &mdiodev->dev; |
---|
| 1448 | + priv->ds->num_ports = QCA8K_NUM_PORTS; |
---|
| 1449 | + priv->ds->configure_vlan_while_not_filtering = true; |
---|
916 | 1450 | priv->ds->priv = priv; |
---|
917 | | - priv->ds->ops = &qca8k_switch_ops; |
---|
| 1451 | + priv->ops = qca8k_switch_ops; |
---|
| 1452 | + priv->ds->ops = &priv->ops; |
---|
918 | 1453 | mutex_init(&priv->reg_mutex); |
---|
919 | 1454 | dev_set_drvdata(&mdiodev->dev, priv); |
---|
920 | 1455 | |
---|
.. | .. |
---|
949 | 1484 | |
---|
950 | 1485 | static int qca8k_suspend(struct device *dev) |
---|
951 | 1486 | { |
---|
952 | | - struct platform_device *pdev = to_platform_device(dev); |
---|
953 | | - struct qca8k_priv *priv = platform_get_drvdata(pdev); |
---|
| 1487 | + struct qca8k_priv *priv = dev_get_drvdata(dev); |
---|
954 | 1488 | |
---|
955 | 1489 | qca8k_set_pm(priv, 0); |
---|
956 | 1490 | |
---|
.. | .. |
---|
959 | 1493 | |
---|
960 | 1494 | static int qca8k_resume(struct device *dev) |
---|
961 | 1495 | { |
---|
962 | | - struct platform_device *pdev = to_platform_device(dev); |
---|
963 | | - struct qca8k_priv *priv = platform_get_drvdata(pdev); |
---|
| 1496 | + struct qca8k_priv *priv = dev_get_drvdata(dev); |
---|
964 | 1497 | |
---|
965 | 1498 | qca8k_set_pm(priv, 1); |
---|
966 | 1499 | |
---|