Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: vsc73xx: Implement the tag_8021q VLAN operations

This patch is a simple implementation of 802.1q tagging in the vsc73xx
driver. Currently, devices with DSA_TAG_PROTO_NONE are not functional.
The VSC73XX family doesn't provide any tag support for external Ethernet
ports.

The only option available is VLAN-based tagging, which requires constant
hardware VLAN filtering. While the VSC73XX family supports provider
bridging, it only supports QinQ without full implementation of 802.1AD.
This means it only allows the doubled 0x8100 TPID.

In the simple port mode, QinQ is enabled to preserve forwarding of
VLAN-tagged frames.

Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://patch.msgid.link/20240713211620.1125910-9-paweldembicki@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Pawel Dembicki and committed by
Jakub Kicinski
e3386ec4 6c87e1a4

+71 -4
+1 -1
drivers/net/dsa/Kconfig
··· 127 127 128 128 config NET_DSA_VITESSE_VSC73XX 129 129 tristate 130 - select NET_DSA_TAG_NONE 130 + select NET_DSA_TAG_VSC73XX_8021Q 131 131 select FIXED_PHY 132 132 select VITESSE_PHY 133 133 select GPIOLIB
+70 -3
drivers/net/dsa/vitesse-vsc73xx-core.c
··· 597 597 * cannot access the tag. (See "Internal frame header" section 598 598 * 3.9.1 in the manual.) 599 599 */ 600 - return DSA_TAG_PROTO_NONE; 600 + return DSA_TAG_PROTO_VSC73XX_8021Q; 601 601 } 602 602 603 603 static int vsc73xx_wait_for_vlan_table_cmd(struct vsc73xx *vsc) ··· 687 687 static int vsc73xx_setup(struct dsa_switch *ds) 688 688 { 689 689 struct vsc73xx *vsc = ds->priv; 690 - int i; 690 + int i, ret; 691 691 692 692 dev_info(vsc->dev, "set up the switch\n"); 693 693 ··· 768 768 769 769 INIT_LIST_HEAD(&vsc->vlans); 770 770 771 - return 0; 771 + rtnl_lock(); 772 + ret = dsa_tag_8021q_register(ds, htons(ETH_P_8021Q)); 773 + rtnl_unlock(); 774 + 775 + return ret; 776 + } 777 + 778 + static void vsc73xx_teardown(struct dsa_switch *ds) 779 + { 780 + rtnl_lock(); 781 + dsa_tag_8021q_unregister(ds); 782 + rtnl_unlock(); 772 783 } 773 784 774 785 static void vsc73xx_init_port(struct vsc73xx *vsc, int port) ··· 1560 1549 vsc73xx_bridge_vlan_remove_port(vsc73xx_vlan, port); 1561 1550 1562 1551 commit_to_hardware = !vsc73xx_tag_8021q_active(dsa_to_port(ds, port)); 1552 + 1563 1553 if (commit_to_hardware) 1564 1554 return vsc73xx_vlan_commit_settings(vsc, port); 1565 1555 1566 1556 return 0; 1557 + } 1558 + 1559 + static int vsc73xx_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid, 1560 + u16 flags) 1561 + { 1562 + bool pvid = flags & BRIDGE_VLAN_INFO_PVID; 1563 + struct vsc73xx_portinfo *portinfo; 1564 + struct vsc73xx *vsc = ds->priv; 1565 + bool commit_to_hardware; 1566 + int ret; 1567 + 1568 + portinfo = &vsc->portinfo[port]; 1569 + 1570 + if (pvid) { 1571 + portinfo->pvid_tag_8021q_configured = true; 1572 + portinfo->pvid_tag_8021q = vid; 1573 + } 1574 + 1575 + commit_to_hardware = vsc73xx_tag_8021q_active(dsa_to_port(ds, port)); 1576 + if (commit_to_hardware) { 1577 + ret = vsc73xx_vlan_commit_settings(vsc, port); 1578 + if (ret) 1579 + return ret; 1580 + } 1581 + 1582 + return vsc73xx_update_vlan_table(vsc, port, vid, true); 1583 + } 1584 + 1585 + static int vsc73xx_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid) 1586 + { 1587 + struct vsc73xx_portinfo *portinfo; 1588 + struct vsc73xx *vsc = ds->priv; 1589 + 1590 + portinfo = &vsc->portinfo[port]; 1591 + 1592 + if (portinfo->pvid_tag_8021q_configured && 1593 + portinfo->pvid_tag_8021q == vid) { 1594 + struct dsa_port *dp = dsa_to_port(ds, port); 1595 + bool commit_to_hardware; 1596 + int err; 1597 + 1598 + portinfo->pvid_tag_8021q_configured = false; 1599 + 1600 + commit_to_hardware = vsc73xx_tag_8021q_active(dp); 1601 + if (commit_to_hardware) { 1602 + err = vsc73xx_vlan_commit_settings(vsc, port); 1603 + if (err) 1604 + return err; 1605 + } 1606 + } 1607 + 1608 + return vsc73xx_update_vlan_table(vsc, port, vid, false); 1567 1609 } 1568 1610 1569 1611 static void vsc73xx_refresh_fwd_map(struct dsa_switch *ds, int port, u8 state) ··· 1708 1644 static const struct dsa_switch_ops vsc73xx_ds_ops = { 1709 1645 .get_tag_protocol = vsc73xx_get_tag_protocol, 1710 1646 .setup = vsc73xx_setup, 1647 + .teardown = vsc73xx_teardown, 1711 1648 .phy_read = vsc73xx_phy_read, 1712 1649 .phy_write = vsc73xx_phy_write, 1713 1650 .get_strings = vsc73xx_get_strings, ··· 1723 1658 .port_vlan_add = vsc73xx_port_vlan_add, 1724 1659 .port_vlan_del = vsc73xx_port_vlan_del, 1725 1660 .phylink_get_caps = vsc73xx_phylink_get_caps, 1661 + .tag_8021q_vlan_add = vsc73xx_tag_8021q_vlan_add, 1662 + .tag_8021q_vlan_del = vsc73xx_tag_8021q_vlan_del, 1726 1663 }; 1727 1664 1728 1665 static int vsc73xx_gpio_get(struct gpio_chip *chip, unsigned int offset)