From 06be1399436f8173dee675611d5097cc77b64469 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Mon, 18 Mar 2024 01:05:05 -0600 Subject: [PATCH] linux: devicetree: Add support for basic Ethernet switching with DSA --- tp2bmc/board/tp2bmc/linux_defconfig | 8 +- tp2bmc/board/tp2bmc/overlay/etc/init.d/S00dsa | 15 + .../tp2bmc/overlay/etc/network/interfaces | 11 + .../tp2bmc/sun8i-t113s-turing-pi2-v2.4.dts | 4 + .../tp2bmc/sun8i-t113s-turing-pi2-v2.5.dts | 9 +- .../board/tp2bmc/sun8i-t113s-turing-pi2.dtsi | 82 + tp2bmc/package/ifupdown-ng/ifupdown-ng.mk | 2 +- tp2bmc/patches/linux/realtek-switch.patch | 1711 +++++++++++++++++ 8 files changed, 1834 insertions(+), 8 deletions(-) create mode 100755 tp2bmc/board/tp2bmc/overlay/etc/init.d/S00dsa create mode 100644 tp2bmc/board/tp2bmc/overlay/etc/network/interfaces create mode 100644 tp2bmc/patches/linux/realtek-switch.patch diff --git a/tp2bmc/board/tp2bmc/linux_defconfig b/tp2bmc/board/tp2bmc/linux_defconfig index 945d4f81..80daa659 100644 --- a/tp2bmc/board/tp2bmc/linux_defconfig +++ b/tp2bmc/board/tp2bmc/linux_defconfig @@ -52,6 +52,9 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_INET_IPCOMP=y CONFIG_INET_UDP_DIAG=y CONFIG_IPV6_TUNNEL=y +CONFIG_BRIDGE=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_TAG_RTL4_A=y CONFIG_NETLINK_DIAG=y CONFIG_UEVENT_HELPER=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -66,6 +69,9 @@ CONFIG_EEPROM_AT24=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y +CONFIG_NET_DSA_REALTEK=y +# CONFIG_NET_DSA_REALTEK_MDIO is not set +CONFIG_NET_DSA_REALTEK_RTL8365MB=y # CONFIG_NET_VENDOR_ALACRITECH is not set # CONFIG_NET_VENDOR_ALLWINNER is not set # CONFIG_NET_VENDOR_AMAZON is not set @@ -114,7 +120,6 @@ CONFIG_STMMAC_ETH=y # CONFIG_NET_VENDOR_WANGXUN is not set # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set -CONFIG_REALTEK_PHY=y # CONFIG_USB_NET_DRIVERS is not set # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y @@ -128,7 +133,6 @@ CONFIG_SERIAL_8250_NR_UARTS=8 CONFIG_SERIAL_8250_DW=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y -CONFIG_I2C_GPIO=y CONFIG_I2C_MV64XXX=y CONFIG_SPI=y CONFIG_SPI_SUN6I=y diff --git a/tp2bmc/board/tp2bmc/overlay/etc/init.d/S00dsa b/tp2bmc/board/tp2bmc/overlay/etc/init.d/S00dsa new file mode 100755 index 00000000..756b9d07 --- /dev/null +++ b/tp2bmc/board/tp2bmc/overlay/etc/init.d/S00dsa @@ -0,0 +1,15 @@ +#!/bin/sh + +# Kind of a hack, don't know where else to put this +# Rename `eth0` to `dsa` on boot, so that it is not confused for a usable +# Ethernet interface + +case "$1" in + start|"") + exec ip link set eth0 name dsa + ;; + *) + echo "Usage: $0 {start}" + exit 1 + ;; +esac diff --git a/tp2bmc/board/tp2bmc/overlay/etc/network/interfaces b/tp2bmc/board/tp2bmc/overlay/etc/network/interfaces new file mode 100644 index 00000000..5dfdae7c --- /dev/null +++ b/tp2bmc/board/tp2bmc/overlay/etc/network/interfaces @@ -0,0 +1,11 @@ +# interface file auto-generated by buildroot + +auto lo +iface lo inet loopback + +auto br0 +iface br0 inet dhcp + bridge-ports node1 node2 node3 node4 ge0 ge1 + pre-up /etc/network/nfs_check + wait-delay 15 + hostname $(hostname) diff --git a/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2-v2.4.dts b/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2-v2.4.dts index 9d59e763..dd31b373 100644 --- a/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2-v2.4.dts +++ b/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2-v2.4.dts @@ -164,6 +164,10 @@ }; }; +ðernet_switch { + reset-gpios = <&pio 6 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + &i2c2 { /* * The TP2 board design includes a 4-pin fan header (J16) and diff --git a/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2-v2.5.dts b/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2-v2.5.dts index 4a638067..9351f49a 100644 --- a/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2-v2.5.dts +++ b/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2-v2.5.dts @@ -9,12 +9,8 @@ compatible = "turing,pi2", "allwinner,sun8i-t113s"; aliases { -#ifndef IS_UBOOT rtc0 = &ext_rtc; rtc1 = &rtc; -#else - rtc0 = &rtc; -#endif }; chosen { @@ -195,7 +191,10 @@ }; }; -#ifndef IS_UBOOT +ðernet_switch { + reset-gpios = <&pio 6 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + &i2c0 { status = "okay"; diff --git a/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2.dtsi b/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2.dtsi index ada2b737..2631ea3b 100644 --- a/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2.dtsi +++ b/tp2bmc/board/tp2bmc/sun8i-t113s-turing-pi2.dtsi @@ -218,6 +218,88 @@ pagesize = <16>; }; + + ethernet_switch: ethernet-switch@5c { + compatible = "realtek,rtl8365mb"; + reg = <0x5c>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "node1"; + phy-handle = <ðphy0>; + phy-mode = "internal"; + }; + ethernet-port@1 { + reg = <1>; + label = "node2"; + phy-handle = <ðphy1>; + phy-mode = "internal"; + }; + ethernet-port@2 { + reg = <2>; + label = "node3"; + phy-handle = <ðphy2>; + phy-mode = "internal"; + }; + ethernet-port@3 { + reg = <3>; + label = "node4"; + phy-handle = <ðphy3>; + phy-mode = "internal"; + }; + ethernet-port@4 { + reg = <4>; + label = "cpu"; + ethernet = <&emac>; + phy-handle = <ðphy4>; + phy-mode = "internal"; + }; + ethernet-port@5 { + reg = <5>; + label = "ge0"; + phy-handle = <ðphy5>; + phy-mode = "internal"; + }; + ethernet-port@6 { + reg = <6>; + label = "ge1"; + phy-handle = <ðphy6>; + phy-mode = "internal"; + }; + }; + + mdio { + compatible = "realtek,smi-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@0 { + reg = <0>; + }; + ethphy1: ethernet-phy@1 { + reg = <1>; + }; + ethphy2: ethernet-phy@2 { + reg = <2>; + }; + ethphy3: ethernet-phy@3 { + reg = <3>; + }; + ethphy4: ethernet-phy@4 { + reg = <4>; + }; + ethphy5: ethernet-phy@5 { + reg = <5>; + }; + ethphy6: ethernet-phy@6 { + reg = <6>; + }; + }; + }; }; &emac { diff --git a/tp2bmc/package/ifupdown-ng/ifupdown-ng.mk b/tp2bmc/package/ifupdown-ng/ifupdown-ng.mk index 1f273487..108c93fb 100644 --- a/tp2bmc/package/ifupdown-ng/ifupdown-ng.mk +++ b/tp2bmc/package/ifupdown-ng/ifupdown-ng.mk @@ -5,7 +5,7 @@ ################################################################################ IFUPDOWN_NG_VERSION = 0.12.1 -IFUPDOWN_NG_SITE = $(call github,ifupdown-ng,ifupdown-ng,$(IFUPDOWN_NG_VERSION)) +IFUPDOWN_NG_SITE = $(call github,ifupdown-ng,ifupdown-ng,ifupdown-ng-$(IFUPDOWN_NG_VERSION)) IFUPDOWN_NG_LICENSE = GPL-2.0+ IFUPDOWN_NG_LICENSE_FILES = COPYING diff --git a/tp2bmc/patches/linux/realtek-switch.patch b/tp2bmc/patches/linux/realtek-switch.patch new file mode 100644 index 00000000..673b2347 --- /dev/null +++ b/tp2bmc/patches/linux/realtek-switch.patch @@ -0,0 +1,1711 @@ +From df33ec7097216f888d1311a6d3fd42ba259524ca Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Wed, 28 Feb 2024 15:34:56 -0700 +Subject: [PATCH 01/11] local: hack in RTL8370MB-CG to dsa driver + +--- + drivers/net/dsa/realtek/rtl8365mb.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index 41ea3b5a42b1..f8c7b2bca205 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -554,6 +554,19 @@ static const struct rtl8365mb_chip_info rtl8365mb_chip_infos[] = { + .jam_table = rtl8365mb_init_jam_8365mb_vc, + .jam_size = ARRAY_SIZE(rtl8365mb_init_jam_8365mb_vc), + }, ++ { ++ .name = "RTL8370MB-CG", ++ .chip_id = 0x6368, ++ .chip_ver = 0x0010, ++ .extints = { ++ { 8, 1, PHY_INTF(MII) | PHY_INTF(TMII) | ++ PHY_INTF(RMII) | PHY_INTF(RGMII) }, ++ { 9, 2, PHY_INTF(MII) | PHY_INTF(TMII) | ++ PHY_INTF(RMII) | PHY_INTF(RGMII) }, ++ }, ++ .jam_table = rtl8365mb_init_jam_8365mb_vc, ++ .jam_size = ARRAY_SIZE(rtl8365mb_init_jam_8365mb_vc), ++ }, + }; + + enum rtl8365mb_stp_state { +-- +2.43.2 + + +From e061ef217a9977a9a044018eb6eeede7be9a00c6 Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Wed, 6 Mar 2024 17:42:37 -0700 +Subject: [PATCH 02/11] local: realtek: cmd_{read,write} -> i2c_addr + +--- + drivers/net/dsa/realtek/realtek-mdio.c | 2 -- + drivers/net/dsa/realtek/realtek-smi.c | 7 +++---- + drivers/net/dsa/realtek/realtek.h | 6 ++---- + drivers/net/dsa/realtek/rtl8365mb.c | 3 +-- + drivers/net/dsa/realtek/rtl8366rb.c | 3 +-- + 5 files changed, 7 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c +index 292e6d087e8b..0f29e6273b4a 100644 +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -184,8 +184,6 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev) + priv->chip_data = (void *)priv + sizeof(*priv); + + priv->clk_delay = var->clk_delay; +- priv->cmd_read = var->cmd_read; +- priv->cmd_write = var->cmd_write; + priv->ops = var->ops; + + priv->write_reg_noack = realtek_mdio_write; +diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c +index ff13563059c5..ca808ac52ebc 100644 +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -208,7 +208,7 @@ static int realtek_smi_read_reg(struct realtek_priv *priv, u32 addr, u32 *data) + realtek_smi_start(priv); + + /* Send READ command */ +- ret = realtek_smi_write_byte(priv, priv->cmd_read); ++ ret = realtek_smi_write_byte(priv, (priv->i2c_addr << 1) | 1); + if (ret) + goto out; + +@@ -249,7 +249,7 @@ static int realtek_smi_write_reg(struct realtek_priv *priv, + realtek_smi_start(priv); + + /* Send WRITE command */ +- ret = realtek_smi_write_byte(priv, priv->cmd_write); ++ ret = realtek_smi_write_byte(priv, (priv->i2c_addr << 1)); + if (ret) + goto out; + +@@ -447,8 +447,7 @@ static int realtek_smi_probe(struct platform_device *pdev) + /* Link forward and backward */ + priv->dev = dev; + priv->clk_delay = var->clk_delay; +- priv->cmd_read = var->cmd_read; +- priv->cmd_write = var->cmd_write; ++ priv->i2c_addr = var->i2c_addr; + priv->ops = var->ops; + + priv->setup_interface = realtek_smi_setup_mdio; +diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h +index 4fa7c6ba874a..9fce9fc1a4a7 100644 +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -59,8 +59,7 @@ struct realtek_priv { + int mdio_addr; + + unsigned int clk_delay; +- u8 cmd_read; +- u8 cmd_write; ++ u8 i2c_addr; + spinlock_t lock; /* Locks around command writes */ + struct dsa_switch *ds; + struct irq_domain *irqdomain; +@@ -120,8 +119,7 @@ struct realtek_variant { + const struct dsa_switch_ops *ds_ops_mdio; + const struct realtek_ops *ops; + unsigned int clk_delay; +- u8 cmd_read; +- u8 cmd_write; ++ u8 i2c_addr; + size_t chip_data_sz; + }; + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index f8c7b2bca205..f07763ff4f59 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -2182,8 +2182,7 @@ const struct realtek_variant rtl8365mb_variant = { + .ds_ops_mdio = &rtl8365mb_switch_ops_mdio, + .ops = &rtl8365mb_ops, + .clk_delay = 10, +- .cmd_read = 0xb9, +- .cmd_write = 0xb8, ++ .i2c_addr = 0x5c, + .chip_data_sz = sizeof(struct rtl8365mb), + }; + EXPORT_SYMBOL_GPL(rtl8365mb_variant); +diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c +index 7868ef237f6c..de06505299da 100644 +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -1890,8 +1890,7 @@ const struct realtek_variant rtl8366rb_variant = { + .ds_ops_mdio = &rtl8366rb_switch_ops_mdio, + .ops = &rtl8366rb_ops, + .clk_delay = 10, +- .cmd_read = 0xa9, +- .cmd_write = 0xa8, ++ .i2c_addr = 0x54, + .chip_data_sz = sizeof(struct rtl8366rb), + }; + EXPORT_SYMBOL_GPL(rtl8366rb_variant); +-- +2.43.2 + + +From 3ce670fc2ce09cabd6f18c9c2028a11c167081dd Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Fri, 8 Mar 2024 22:38:34 -0700 +Subject: [PATCH 03/11] local: realtek: clean up `chip_data` + +--- + drivers/net/dsa/realtek/realtek-mdio.c | 1 - + drivers/net/dsa/realtek/realtek-smi.c | 1 - + drivers/net/dsa/realtek/realtek.h | 2 +- + drivers/net/dsa/realtek/rtl8365mb.c | 38 +++++++++++++------------- + drivers/net/dsa/realtek/rtl8366rb.c | 8 +++--- + 5 files changed, 24 insertions(+), 26 deletions(-) + +diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c +index 0f29e6273b4a..cde06e1ffa34 100644 +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -181,7 +181,6 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev) + priv->mdio_addr = mdiodev->addr; + priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; +- priv->chip_data = (void *)priv + sizeof(*priv); + + priv->clk_delay = var->clk_delay; + priv->ops = var->ops; +diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c +index ca808ac52ebc..b6dc3798600c 100644 +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -423,7 +423,6 @@ static int realtek_smi_probe(struct platform_device *pdev) + priv = devm_kzalloc(dev, sizeof(*priv) + var->chip_data_sz, GFP_KERNEL); + if (!priv) + return -ENOMEM; +- priv->chip_data = (void *)priv + sizeof(*priv); + + mutex_init(&priv->map_lock); + +diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h +index 9fce9fc1a4a7..61adcd66703f 100644 +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -79,7 +79,7 @@ struct realtek_priv { + int vlan4k_enabled; + + char buf[4096]; +- void *chip_data; /* Per-chip extra variant data */ ++ char chip_data[]; /* Per-chip extra variant data */ + }; + + /* +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index f07763ff4f59..205645ded149 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -852,7 +852,7 @@ static int rtl8365mb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum, + static const struct rtl8365mb_extint * + rtl8365mb_get_port_extint(struct realtek_priv *priv, int port) + { +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + int i; + + for (i = 0; i < RTL8365MB_MAX_NUM_EXTINTS; i++) { +@@ -877,7 +877,7 @@ rtl8365mb_get_tag_protocol(struct dsa_switch *ds, int port, + struct rtl8365mb_cpu *cpu; + struct rtl8365mb *mb; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + cpu = &mb->cpu; + + if (cpu->position == RTL8365MB_CPU_POS_BEFORE_CRC) +@@ -1105,7 +1105,7 @@ static void rtl8365mb_phylink_mac_link_down(struct dsa_switch *ds, int port, + struct rtl8365mb *mb; + int ret; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + p = &mb->ports[port]; + cancel_delayed_work_sync(&p->mib_work); + +@@ -1133,7 +1133,7 @@ static void rtl8365mb_phylink_mac_link_up(struct dsa_switch *ds, int port, + struct rtl8365mb *mb; + int ret; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + p = &mb->ports[port]; + schedule_delayed_work(&p->mib_work, 0); + +@@ -1289,7 +1289,7 @@ static void rtl8365mb_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *da + int ret; + int i; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + + mutex_lock(&mb->mib_lock); + for (i = 0; i < RTL8365MB_MIB_END; i++) { +@@ -1336,7 +1336,7 @@ static void rtl8365mb_get_phy_stats(struct dsa_switch *ds, int port, + struct rtl8365mb_mib_counter *mib; + struct rtl8365mb *mb; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + mib = &rtl8365mb_mib_counters[RTL8365MB_MIB_dot3StatsSymbolErrors]; + + mutex_lock(&mb->mib_lock); +@@ -1373,7 +1373,7 @@ static void rtl8365mb_get_mac_stats(struct dsa_switch *ds, int port, + int ret; + int i; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + + mutex_lock(&mb->mib_lock); + for (i = 0; i < RTL8365MB_MIB_END; i++) { +@@ -1437,7 +1437,7 @@ static void rtl8365mb_get_ctrl_stats(struct dsa_switch *ds, int port, + struct rtl8365mb_mib_counter *mib; + struct rtl8365mb *mb; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + mib = &rtl8365mb_mib_counters[RTL8365MB_MIB_dot3ControlInUnknownOpcodes]; + + mutex_lock(&mb->mib_lock); +@@ -1465,7 +1465,7 @@ static void rtl8365mb_stats_update(struct realtek_priv *priv, int port) + [RTL8365MB_MIB_dot3StatsFCSErrors] = 1, + [RTL8365MB_MIB_dot3StatsLateCollisions] = 1, + }; +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + struct rtnl_link_stats64 *stats; + int ret; + int i; +@@ -1544,7 +1544,7 @@ static void rtl8365mb_get_stats64(struct dsa_switch *ds, int port, + struct rtl8365mb_port *p; + struct rtl8365mb *mb; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + p = &mb->ports[port]; + + spin_lock(&p->stats_lock); +@@ -1554,7 +1554,7 @@ static void rtl8365mb_get_stats64(struct dsa_switch *ds, int port, + + static void rtl8365mb_stats_setup(struct realtek_priv *priv) + { +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + int i; + + /* Per-chip global mutex to protect MIB counter access, since doing +@@ -1580,7 +1580,7 @@ static void rtl8365mb_stats_setup(struct realtek_priv *priv) + + static void rtl8365mb_stats_teardown(struct realtek_priv *priv) + { +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + int i; + + for (i = 0; i < priv->num_ports; i++) { +@@ -1707,7 +1707,7 @@ static int rtl8365mb_irq_disable(struct realtek_priv *priv) + + static int rtl8365mb_irq_setup(struct realtek_priv *priv) + { +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + struct device_node *intc; + u32 irq_trig; + int virq; +@@ -1826,7 +1826,7 @@ static int rtl8365mb_irq_setup(struct realtek_priv *priv) + + static void rtl8365mb_irq_teardown(struct realtek_priv *priv) + { +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + int virq; + int i; + +@@ -1848,7 +1848,7 @@ static void rtl8365mb_irq_teardown(struct realtek_priv *priv) + + static int rtl8365mb_cpu_config(struct realtek_priv *priv) + { +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + struct rtl8365mb_cpu *cpu = &mb->cpu; + u32 val; + int ret; +@@ -1882,7 +1882,7 @@ static int rtl8365mb_change_tag_protocol(struct dsa_switch *ds, + struct rtl8365mb_cpu *cpu; + struct rtl8365mb *mb; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + cpu = &mb->cpu; + + switch (proto) { +@@ -1908,7 +1908,7 @@ static int rtl8365mb_change_tag_protocol(struct dsa_switch *ds, + + static int rtl8365mb_switch_init(struct realtek_priv *priv) + { +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + const struct rtl8365mb_chip_info *ci; + int ret; + int i; +@@ -1961,7 +1961,7 @@ static int rtl8365mb_setup(struct dsa_switch *ds) + int ret; + int i; + +- mb = priv->chip_data; ++ mb = (struct rtl8365mb *)priv->chip_data; + cpu = &mb->cpu; + + ret = rtl8365mb_reset_chip(priv); +@@ -2085,7 +2085,7 @@ static int rtl8365mb_get_chip_id_and_ver(struct regmap *map, u32 *id, u32 *ver) + + static int rtl8365mb_detect(struct realtek_priv *priv) + { +- struct rtl8365mb *mb = priv->chip_data; ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; + u32 chip_id; + u32 chip_ver; + int ret; +diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c +index de06505299da..23dee1ce1d4a 100644 +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -812,7 +812,7 @@ static int rtl8366rb_setup(struct dsa_switch *ds) + int ret; + int i; + +- rb = priv->chip_data; ++ rb = (struct rtl8366rb *)priv->chip_data; + + ret = regmap_read(priv->map, RTL8366RB_CHIP_ID_REG, &chip_id); + if (ret) { +@@ -1299,7 +1299,7 @@ static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port, + struct rtl8366rb *rb; + int ret; + +- rb = priv->chip_data; ++ rb = (struct rtl8366rb *)priv->chip_data; + + dev_dbg(priv->dev, "port %d: %s VLAN filtering\n", port, + vlan_filtering ? "enable" : "disable"); +@@ -1409,7 +1409,7 @@ static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) + int i; + + /* Cache the per-port MTU setting */ +- rb = priv->chip_data; ++ rb = (struct rtl8366rb *)priv->chip_data; + rb->max_mtu[port] = new_mtu; + + /* Roof out the MTU for the entire switch to the greatest +@@ -1615,7 +1615,7 @@ static int rtl8366rb_set_mc_index(struct realtek_priv *priv, int port, int index + bool pvid_enabled; + int ret; + +- rb = priv->chip_data; ++ rb = (struct rtl8366rb *)priv->chip_data; + pvid_enabled = !!index; + + if (port >= priv->num_ports || index >= RTL8366RB_NUM_VLANS) +-- +2.43.2 + + +From 1bd0e9b71f9b092592db87488920be09a2a35bc2 Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Fri, 8 Mar 2024 22:56:42 -0700 +Subject: [PATCH 04/11] local: realtek: simplify/clean up regmap config + +--- + drivers/net/dsa/realtek/realtek-mdio.c | 21 ++------------------- + drivers/net/dsa/realtek/realtek-smi.c | 20 ++------------------ + 2 files changed, 4 insertions(+), 37 deletions(-) + +diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c +index cde06e1ffa34..8622d9c0833d 100644 +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -114,12 +114,8 @@ static void realtek_mdio_unlock(void *ctx) + } + + static const struct regmap_config realtek_mdio_regmap_config = { +- .reg_bits = 10, /* A4..A0 R4..R0 */ ++ .reg_bits = 16, + .val_bits = 16, +- .reg_stride = 1, +- /* PHY regs are at 0x8000 */ +- .max_register = 0xffff, +- .reg_format_endian = REGMAP_ENDIAN_BIG, + .reg_read = realtek_mdio_read, + .reg_write = realtek_mdio_write, + .cache_type = REGCACHE_NONE, +@@ -127,19 +123,6 @@ static const struct regmap_config realtek_mdio_regmap_config = { + .unlock = realtek_mdio_unlock, + }; + +-static const struct regmap_config realtek_mdio_nolock_regmap_config = { +- .reg_bits = 10, /* A4..A0 R4..R0 */ +- .val_bits = 16, +- .reg_stride = 1, +- /* PHY regs are at 0x8000 */ +- .max_register = 0xffff, +- .reg_format_endian = REGMAP_ENDIAN_BIG, +- .reg_read = realtek_mdio_read, +- .reg_write = realtek_mdio_write, +- .cache_type = REGCACHE_NONE, +- .disable_locking = true, +-}; +- + static int realtek_mdio_probe(struct mdio_device *mdiodev) + { + struct realtek_priv *priv; +@@ -170,7 +153,7 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev) + return ret; + } + +- rc = realtek_mdio_nolock_regmap_config; ++ rc.disable_locking = true; + priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); + if (IS_ERR(priv->map_nolock)) { + ret = PTR_ERR(priv->map_nolock); +diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c +index b6dc3798600c..26d60dbf01bd 100644 +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -325,11 +325,8 @@ static void realtek_smi_unlock(void *ctx) + } + + static const struct regmap_config realtek_smi_regmap_config = { +- .reg_bits = 10, /* A4..A0 R4..R0 */ ++ .reg_bits = 16, + .val_bits = 16, +- .reg_stride = 1, +- /* PHY regs are at 0x8000 */ +- .max_register = 0xffff, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .reg_read = realtek_smi_read, + .reg_write = realtek_smi_write, +@@ -338,19 +335,6 @@ static const struct regmap_config realtek_smi_regmap_config = { + .unlock = realtek_smi_unlock, + }; + +-static const struct regmap_config realtek_smi_nolock_regmap_config = { +- .reg_bits = 10, /* A4..A0 R4..R0 */ +- .val_bits = 16, +- .reg_stride = 1, +- /* PHY regs are at 0x8000 */ +- .max_register = 0xffff, +- .reg_format_endian = REGMAP_ENDIAN_BIG, +- .reg_read = realtek_smi_read, +- .reg_write = realtek_smi_write, +- .cache_type = REGCACHE_NONE, +- .disable_locking = true, +-}; +- + static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) + { + struct realtek_priv *priv = bus->priv; +@@ -435,7 +419,7 @@ static int realtek_smi_probe(struct platform_device *pdev) + return ret; + } + +- rc = realtek_smi_nolock_regmap_config; ++ rc.disable_locking = true; + priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); + if (IS_ERR(priv->map_nolock)) { + ret = PTR_ERR(priv->map_nolock); +-- +2.43.2 + + +From 42670d4213d6c03b52707408810e309691d01b5b Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Mon, 11 Mar 2024 23:11:55 -0600 +Subject: [PATCH 05/11] local: realtek: kill off `realtek_smi_write_reg_noack` + +--- + drivers/net/dsa/realtek/realtek-mdio.c | 2 -- + drivers/net/dsa/realtek/realtek-smi.c | 26 +++----------------------- + drivers/net/dsa/realtek/realtek.h | 1 - + drivers/net/dsa/realtek/rtl8365mb.c | 4 ++-- + drivers/net/dsa/realtek/rtl8366rb.c | 4 ++-- + 5 files changed, 7 insertions(+), 30 deletions(-) + +diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c +index 8622d9c0833d..f8c479d0e5a1 100644 +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -168,8 +168,6 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev) + priv->clk_delay = var->clk_delay; + priv->ops = var->ops; + +- priv->write_reg_noack = realtek_mdio_write; +- + np = dev->of_node; + + dev_set_drvdata(dev, priv); +diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c +index 26d60dbf01bd..53a6018d54b8 100644 +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -162,12 +162,6 @@ static int realtek_smi_write_byte(struct realtek_priv *priv, u8 data) + return realtek_smi_wait_for_ack(priv); + } + +-static int realtek_smi_write_byte_noack(struct realtek_priv *priv, u8 data) +-{ +- realtek_smi_write_bits(priv, data, 8); +- return 0; +-} +- + static int realtek_smi_read_byte0(struct realtek_priv *priv, u8 *data) + { + u32 t; +@@ -238,8 +232,7 @@ static int realtek_smi_read_reg(struct realtek_priv *priv, u32 addr, u32 *data) + return ret; + } + +-static int realtek_smi_write_reg(struct realtek_priv *priv, +- u32 addr, u32 data, bool ack) ++static int realtek_smi_write_reg(struct realtek_priv *priv, u32 addr, u32 data) + { + unsigned long flags; + int ret; +@@ -269,10 +262,7 @@ static int realtek_smi_write_reg(struct realtek_priv *priv, + goto out; + + /* Write DATA[15:8] */ +- if (ack) +- ret = realtek_smi_write_byte(priv, data >> 8); +- else +- ret = realtek_smi_write_byte_noack(priv, data >> 8); ++ ret = realtek_smi_write_byte(priv, data >> 8); + if (ret) + goto out; + +@@ -285,22 +275,13 @@ static int realtek_smi_write_reg(struct realtek_priv *priv, + return ret; + } + +-/* There is one single case when we need to use this accessor and that +- * is when issueing soft reset. Since the device reset as soon as we write +- * that bit, no ACK will come back for natural reasons. +- */ +-static int realtek_smi_write_reg_noack(void *ctx, u32 reg, u32 val) +-{ +- return realtek_smi_write_reg(ctx, reg, val, false); +-} +- + /* Regmap accessors */ + + static int realtek_smi_write(void *ctx, u32 reg, u32 val) + { + struct realtek_priv *priv = ctx; + +- return realtek_smi_write_reg(priv, reg, val, true); ++ return realtek_smi_write_reg(priv, reg, val); + } + + static int realtek_smi_read(void *ctx, u32 reg, u32 *val) +@@ -434,7 +415,6 @@ static int realtek_smi_probe(struct platform_device *pdev) + priv->ops = var->ops; + + priv->setup_interface = realtek_smi_setup_mdio; +- priv->write_reg_noack = realtek_smi_write_reg_noack; + + dev_set_drvdata(dev, priv); + spin_lock_init(&priv->lock); +diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h +index 61adcd66703f..eed9bb3ed10a 100644 +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -73,7 +73,6 @@ struct realtek_priv { + + const struct realtek_ops *ops; + int (*setup_interface)(struct dsa_switch *ds); +- int (*write_reg_noack)(void *ctx, u32 addr, u32 data); + + int vlan_enabled; + int vlan4k_enabled; +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index 205645ded149..b723ade207c9 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -1940,8 +1940,8 @@ static int rtl8365mb_reset_chip(struct realtek_priv *priv) + { + u32 val; + +- priv->write_reg_noack(priv, RTL8365MB_CHIP_RESET_REG, +- FIELD_PREP(RTL8365MB_CHIP_RESET_HW_MASK, 1)); ++ regmap_write(priv->map, RTL8365MB_CHIP_RESET_REG, ++ FIELD_PREP(RTL8365MB_CHIP_RESET_HW_MASK, 1)); + + /* Realtek documentation says the chip needs 1 second to reset. Sleep + * for 100 ms before accessing any registers to prevent ACK timeouts. +diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c +index 23dee1ce1d4a..3f2084bc0b02 100644 +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -1760,8 +1760,8 @@ static int rtl8366rb_reset_chip(struct realtek_priv *priv) + u32 val; + int ret; + +- priv->write_reg_noack(priv, RTL8366RB_RESET_CTRL_REG, +- RTL8366RB_CHIP_CTRL_RESET_HW); ++ regmap_write(priv->map, RTL8366RB_RESET_CTRL_REG, ++ RTL8366RB_CHIP_CTRL_RESET_HW); + do { + usleep_range(20000, 25000); + ret = regmap_read(priv->map, RTL8366RB_RESET_CTRL_REG, &val); +-- +2.43.2 + + +From 53bf34da29f84eba84a0c22387f476a0a13d6b61 Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Mon, 11 Mar 2024 23:19:50 -0600 +Subject: [PATCH 06/11] local: realtek: become an i2c driver, not platform + +--- + drivers/net/dsa/realtek/Kconfig | 1 + + drivers/net/dsa/realtek/realtek-mdio.c | 1 - + drivers/net/dsa/realtek/realtek-smi.c | 293 ++----------------------- + drivers/net/dsa/realtek/realtek.h | 4 - + 4 files changed, 17 insertions(+), 282 deletions(-) + +diff --git a/drivers/net/dsa/realtek/Kconfig b/drivers/net/dsa/realtek/Kconfig +index 060165a85fb7..ee74ef09511d 100644 +--- a/drivers/net/dsa/realtek/Kconfig ++++ b/drivers/net/dsa/realtek/Kconfig +@@ -31,6 +31,7 @@ config NET_DSA_REALTEK_SMI + depends on NET_DSA_REALTEK_RTL8365MB || NET_DSA_REALTEK_RTL8366RB + depends on NET_DSA_REALTEK_RTL8365MB || !NET_DSA_REALTEK_RTL8365MB + depends on NET_DSA_REALTEK_RTL8366RB || !NET_DSA_REALTEK_RTL8366RB ++ select REGMAP_I2C + help + Select to enable support for registering switches connected + through SMI. +diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c +index f8c479d0e5a1..d9bd65842fb9 100644 +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -165,7 +165,6 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev) + priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; + +- priv->clk_delay = var->clk_delay; + priv->ops = var->ops; + + np = dev->of_node; +diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c +index 53a6018d54b8..1aeb32a1c068 100644 +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -34,263 +34,13 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include + + #include "realtek.h" + +-#define REALTEK_SMI_ACK_RETRY_COUNT 5 +- +-static inline void realtek_smi_clk_delay(struct realtek_priv *priv) +-{ +- ndelay(priv->clk_delay); +-} +- +-static void realtek_smi_start(struct realtek_priv *priv) +-{ +- /* Set GPIO pins to output mode, with initial state: +- * SCK = 0, SDA = 1 +- */ +- gpiod_direction_output(priv->mdc, 0); +- gpiod_direction_output(priv->mdio, 1); +- realtek_smi_clk_delay(priv); +- +- /* CLK 1: 0 -> 1, 1 -> 0 */ +- gpiod_set_value(priv->mdc, 1); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdc, 0); +- realtek_smi_clk_delay(priv); +- +- /* CLK 2: */ +- gpiod_set_value(priv->mdc, 1); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdio, 0); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdc, 0); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdio, 1); +-} +- +-static void realtek_smi_stop(struct realtek_priv *priv) +-{ +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdio, 0); +- gpiod_set_value(priv->mdc, 1); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdio, 1); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdc, 1); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdc, 0); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdc, 1); +- +- /* Add a click */ +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdc, 0); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdc, 1); +- +- /* Set GPIO pins to input mode */ +- gpiod_direction_input(priv->mdio); +- gpiod_direction_input(priv->mdc); +-} +- +-static void realtek_smi_write_bits(struct realtek_priv *priv, u32 data, u32 len) +-{ +- for (; len > 0; len--) { +- realtek_smi_clk_delay(priv); +- +- /* Prepare data */ +- gpiod_set_value(priv->mdio, !!(data & (1 << (len - 1)))); +- realtek_smi_clk_delay(priv); +- +- /* Clocking */ +- gpiod_set_value(priv->mdc, 1); +- realtek_smi_clk_delay(priv); +- gpiod_set_value(priv->mdc, 0); +- } +-} +- +-static void realtek_smi_read_bits(struct realtek_priv *priv, u32 len, u32 *data) +-{ +- gpiod_direction_input(priv->mdio); +- +- for (*data = 0; len > 0; len--) { +- u32 u; +- +- realtek_smi_clk_delay(priv); +- +- /* Clocking */ +- gpiod_set_value(priv->mdc, 1); +- realtek_smi_clk_delay(priv); +- u = !!gpiod_get_value(priv->mdio); +- gpiod_set_value(priv->mdc, 0); +- +- *data |= (u << (len - 1)); +- } +- +- gpiod_direction_output(priv->mdio, 0); +-} +- +-static int realtek_smi_wait_for_ack(struct realtek_priv *priv) +-{ +- int retry_cnt; +- +- retry_cnt = 0; +- do { +- u32 ack; +- +- realtek_smi_read_bits(priv, 1, &ack); +- if (ack == 0) +- break; +- +- if (++retry_cnt > REALTEK_SMI_ACK_RETRY_COUNT) { +- dev_err(priv->dev, "ACK timeout\n"); +- return -ETIMEDOUT; +- } +- } while (1); +- +- return 0; +-} +- +-static int realtek_smi_write_byte(struct realtek_priv *priv, u8 data) +-{ +- realtek_smi_write_bits(priv, data, 8); +- return realtek_smi_wait_for_ack(priv); +-} +- +-static int realtek_smi_read_byte0(struct realtek_priv *priv, u8 *data) +-{ +- u32 t; +- +- /* Read data */ +- realtek_smi_read_bits(priv, 8, &t); +- *data = (t & 0xff); +- +- /* Send an ACK */ +- realtek_smi_write_bits(priv, 0x00, 1); +- +- return 0; +-} +- +-static int realtek_smi_read_byte1(struct realtek_priv *priv, u8 *data) +-{ +- u32 t; +- +- /* Read data */ +- realtek_smi_read_bits(priv, 8, &t); +- *data = (t & 0xff); +- +- /* Send an ACK */ +- realtek_smi_write_bits(priv, 0x01, 1); +- +- return 0; +-} +- +-static int realtek_smi_read_reg(struct realtek_priv *priv, u32 addr, u32 *data) +-{ +- unsigned long flags; +- u8 lo = 0; +- u8 hi = 0; +- int ret; +- +- spin_lock_irqsave(&priv->lock, flags); +- +- realtek_smi_start(priv); +- +- /* Send READ command */ +- ret = realtek_smi_write_byte(priv, (priv->i2c_addr << 1) | 1); +- if (ret) +- goto out; +- +- /* Set ADDR[7:0] */ +- ret = realtek_smi_write_byte(priv, addr & 0xff); +- if (ret) +- goto out; +- +- /* Set ADDR[15:8] */ +- ret = realtek_smi_write_byte(priv, addr >> 8); +- if (ret) +- goto out; +- +- /* Read DATA[7:0] */ +- realtek_smi_read_byte0(priv, &lo); +- /* Read DATA[15:8] */ +- realtek_smi_read_byte1(priv, &hi); +- +- *data = ((u32)lo) | (((u32)hi) << 8); +- +- ret = 0; +- +- out: +- realtek_smi_stop(priv); +- spin_unlock_irqrestore(&priv->lock, flags); +- +- return ret; +-} +- +-static int realtek_smi_write_reg(struct realtek_priv *priv, u32 addr, u32 data) +-{ +- unsigned long flags; +- int ret; +- +- spin_lock_irqsave(&priv->lock, flags); +- +- realtek_smi_start(priv); +- +- /* Send WRITE command */ +- ret = realtek_smi_write_byte(priv, (priv->i2c_addr << 1)); +- if (ret) +- goto out; +- +- /* Set ADDR[7:0] */ +- ret = realtek_smi_write_byte(priv, addr & 0xff); +- if (ret) +- goto out; +- +- /* Set ADDR[15:8] */ +- ret = realtek_smi_write_byte(priv, addr >> 8); +- if (ret) +- goto out; +- +- /* Write DATA[7:0] */ +- ret = realtek_smi_write_byte(priv, data & 0xff); +- if (ret) +- goto out; +- +- /* Write DATA[15:8] */ +- ret = realtek_smi_write_byte(priv, data >> 8); +- if (ret) +- goto out; +- +- ret = 0; +- +- out: +- realtek_smi_stop(priv); +- spin_unlock_irqrestore(&priv->lock, flags); +- +- return ret; +-} +- +-/* Regmap accessors */ +- +-static int realtek_smi_write(void *ctx, u32 reg, u32 val) +-{ +- struct realtek_priv *priv = ctx; +- +- return realtek_smi_write_reg(priv, reg, val); +-} +- +-static int realtek_smi_read(void *ctx, u32 reg, u32 *val) +-{ +- struct realtek_priv *priv = ctx; +- +- return realtek_smi_read_reg(priv, reg, val); +-} +- + static void realtek_smi_lock(void *ctx) + { + struct realtek_priv *priv = ctx; +@@ -309,8 +59,7 @@ static const struct regmap_config realtek_smi_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + .reg_format_endian = REGMAP_ENDIAN_BIG, +- .reg_read = realtek_smi_read, +- .reg_write = realtek_smi_write, ++ .val_format_endian = REGMAP_ENDIAN_LITTLE, + .cache_type = REGCACHE_NONE, + .lock = realtek_smi_lock, + .unlock = realtek_smi_unlock, +@@ -373,10 +122,10 @@ static int realtek_smi_setup_mdio(struct dsa_switch *ds) + return ret; + } + +-static int realtek_smi_probe(struct platform_device *pdev) ++static int realtek_smi_probe(struct i2c_client *client) + { + const struct realtek_variant *var; +- struct device *dev = &pdev->dev; ++ struct device *dev = &client->dev; + struct realtek_priv *priv; + struct regmap_config rc; + struct device_node *np; +@@ -393,7 +142,7 @@ static int realtek_smi_probe(struct platform_device *pdev) + + rc = realtek_smi_regmap_config; + rc.lock_arg = priv; +- priv->map = devm_regmap_init(dev, NULL, priv, &rc); ++ priv->map = devm_regmap_init_i2c(client, &rc); + if (IS_ERR(priv->map)) { + ret = PTR_ERR(priv->map); + dev_err(dev, "regmap init failed: %d\n", ret); +@@ -401,7 +150,7 @@ static int realtek_smi_probe(struct platform_device *pdev) + } + + rc.disable_locking = true; +- priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); ++ priv->map_nolock = devm_regmap_init_i2c(client, &rc); + if (IS_ERR(priv->map_nolock)) { + ret = PTR_ERR(priv->map_nolock); + dev_err(dev, "regmap init failed: %d\n", ret); +@@ -410,13 +159,11 @@ static int realtek_smi_probe(struct platform_device *pdev) + + /* Link forward and backward */ + priv->dev = dev; +- priv->clk_delay = var->clk_delay; +- priv->i2c_addr = var->i2c_addr; + priv->ops = var->ops; + + priv->setup_interface = realtek_smi_setup_mdio; + +- dev_set_drvdata(dev, priv); ++ i2c_set_clientdata(client, priv); + spin_lock_init(&priv->lock); + + /* TODO: if power is software controlled, set up any regulators here */ +@@ -435,14 +182,6 @@ static int realtek_smi_probe(struct platform_device *pdev) + dev_dbg(dev, "deasserted RESET\n"); + } + +- /* Fetch MDIO pins */ +- priv->mdc = devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW); +- if (IS_ERR(priv->mdc)) +- return PTR_ERR(priv->mdc); +- priv->mdio = devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW); +- if (IS_ERR(priv->mdio)) +- return PTR_ERR(priv->mdio); +- + priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds"); + + ret = priv->ops->detect(priv); +@@ -468,12 +207,12 @@ static int realtek_smi_probe(struct platform_device *pdev) + return 0; + } + +-static int realtek_smi_remove(struct platform_device *pdev) ++static void realtek_smi_remove(struct i2c_client *client) + { +- struct realtek_priv *priv = platform_get_drvdata(pdev); ++ struct realtek_priv *priv = i2c_get_clientdata(client); + + if (!priv) +- return 0; ++ return; + + dsa_unregister_switch(priv->ds); + if (priv->slave_mii_bus) +@@ -483,19 +222,19 @@ static int realtek_smi_remove(struct platform_device *pdev) + if (priv->reset) + gpiod_set_value(priv->reset, 1); + +- return 0; ++ return; + } + +-static void realtek_smi_shutdown(struct platform_device *pdev) ++static void realtek_smi_shutdown(struct i2c_client *client) + { +- struct realtek_priv *priv = platform_get_drvdata(pdev); ++ struct realtek_priv *priv = i2c_get_clientdata(client); + + if (!priv) + return; + + dsa_switch_shutdown(priv->ds); + +- platform_set_drvdata(pdev, NULL); ++ i2c_set_clientdata(client, NULL); + } + + static const struct of_device_id realtek_smi_of_match[] = { +@@ -515,7 +254,7 @@ static const struct of_device_id realtek_smi_of_match[] = { + }; + MODULE_DEVICE_TABLE(of, realtek_smi_of_match); + +-static struct platform_driver realtek_smi_driver = { ++static struct i2c_driver realtek_smi_driver = { + .driver = { + .name = "realtek-smi", + .of_match_table = realtek_smi_of_match, +@@ -524,7 +263,7 @@ static struct platform_driver realtek_smi_driver = { + .remove = realtek_smi_remove, + .shutdown = realtek_smi_shutdown, + }; +-module_platform_driver(realtek_smi_driver); ++module_i2c_driver(realtek_smi_driver); + + MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface"); +diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h +index eed9bb3ed10a..cd2b9e774044 100644 +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -49,8 +49,6 @@ struct rtl8366_vlan_4k { + struct realtek_priv { + struct device *dev; + struct gpio_desc *reset; +- struct gpio_desc *mdc; +- struct gpio_desc *mdio; + struct regmap *map; + struct regmap *map_nolock; + struct mutex map_lock; +@@ -58,8 +56,6 @@ struct realtek_priv { + struct mii_bus *bus; + int mdio_addr; + +- unsigned int clk_delay; +- u8 i2c_addr; + spinlock_t lock; /* Locks around command writes */ + struct dsa_switch *ds; + struct irq_domain *irqdomain; +-- +2.43.2 + + +From 8f6ff7666048234af439687962ed8fc72209c542 Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Wed, 13 Mar 2024 19:48:18 -0600 +Subject: [PATCH 07/11] local: realtek: Implement "Realtek"/"RTK" I2C mode + +--- + drivers/net/dsa/realtek/realtek-smi.c | 79 ++++++++++++++++++++++++++- + 1 file changed, 78 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c +index 1aeb32a1c068..01e0634ce999 100644 +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -41,6 +41,75 @@ + + #include "realtek.h" + ++static int realtek_smi_rtk_read(void *ctx, const void *reg, size_t reg_size, ++ void *val, size_t val_size) ++{ ++ struct device *dev = ctx; ++ struct i2c_client *i2c = to_i2c_client(dev); ++ int ret; ++ ++ /* In "Realtek" I2C mode, read transfers aren't quite the same as those ++ * of standard I2C. A conventional I2C read involves a write transfer ++ * to specify the register, followed by a read transfer to retrieve the ++ * value. The "Realtek" mode uses a single transfer, but the adapter ++ * sends 2 extra bytes after the address byte to specify the register ++ * before the bus turns around to complete the read operation. ++ * ++ * This can be accomplished through prudent use of the NOSTART flag to ++ * insert the register bytes into the middle of a read transfer without ++ * the device being any the wiser. ++ */ ++ struct i2c_msg xfer[] = { ++ /* Start a transfer and send only the start byte ++ * (address and R/W̅ bit) */ ++ { ++ .addr = i2c->addr, ++ .flags = I2C_M_RD, ++ .len = 0 ++ }, ++ ++ /* Send 2 extra bytes to specify the register */ ++ { ++ .addr = i2c->addr, ++ .flags = I2C_M_NOSTART, ++ .len = reg_size, ++ .buf = (void *)reg ++ }, ++ ++ /* Now turn the bus around and finish the read */ ++ { ++ .addr = i2c->addr, ++ .flags = I2C_M_RD | I2C_M_NOSTART, ++ .len = val_size, ++ .buf = val ++ } ++ }; ++ ++ ret = i2c_transfer(i2c->adapter, xfer, ARRAY_SIZE(xfer)); ++ if (ret == ARRAY_SIZE(xfer)) ++ return 0; ++ else if (ret < 0) ++ return ret; ++ else ++ return -EIO; ++} ++ ++static int realtek_smi_rtk_write(void *ctx, const void *data, size_t count) ++{ ++ struct device *dev = ctx; ++ struct i2c_client *i2c = to_i2c_client(dev); ++ int ret; ++ ++ /* Writes, on the other hand, are no different in 'rtk' mode. */ ++ ret = i2c_master_send(i2c, data, count); ++ if (ret == count) ++ return 0; ++ else if (ret < 0) ++ return ret; ++ else ++ return -EIO; ++} ++ + static void realtek_smi_lock(void *ctx) + { + struct realtek_priv *priv = ctx; +@@ -58,8 +127,10 @@ static void realtek_smi_unlock(void *ctx) + static const struct regmap_config realtek_smi_regmap_config = { + .reg_bits = 16, + .val_bits = 16, +- .reg_format_endian = REGMAP_ENDIAN_BIG, ++ .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_LITTLE, ++ .read = realtek_smi_rtk_read, ++ .write = realtek_smi_rtk_write, + .cache_type = REGCACHE_NONE, + .lock = realtek_smi_lock, + .unlock = realtek_smi_unlock, +@@ -134,6 +205,12 @@ static int realtek_smi_probe(struct i2c_client *client) + var = of_device_get_match_data(dev); + np = dev->of_node; + ++ /* The "Realtek" protocol variant requires nonstandard functionality */ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_NOSTART)) { ++ dev_err(dev, "'rtk' mode needs bus with NOSTART support\n"); ++ return -ENODEV; ++ } ++ + priv = devm_kzalloc(dev, sizeof(*priv) + var->chip_data_sz, GFP_KERNEL); + if (!priv) + return -ENOMEM; +-- +2.43.2 + + +From 675d9d3af6a2e07dd71577876f2b2bffb422f794 Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Tue, 12 Mar 2024 03:41:04 -0600 +Subject: [PATCH 08/11] local: realtek: add back GPIO support + +--- + drivers/net/dsa/realtek/Kconfig | 1 + + drivers/net/dsa/realtek/realtek-smi.c | 114 ++++++++++++++++++++++++++ + 2 files changed, 115 insertions(+) + +diff --git a/drivers/net/dsa/realtek/Kconfig b/drivers/net/dsa/realtek/Kconfig +index ee74ef09511d..81a0e0270557 100644 +--- a/drivers/net/dsa/realtek/Kconfig ++++ b/drivers/net/dsa/realtek/Kconfig +@@ -31,6 +31,7 @@ config NET_DSA_REALTEK_SMI + depends on NET_DSA_REALTEK_RTL8365MB || NET_DSA_REALTEK_RTL8366RB + depends on NET_DSA_REALTEK_RTL8365MB || !NET_DSA_REALTEK_RTL8365MB + depends on NET_DSA_REALTEK_RTL8366RB || !NET_DSA_REALTEK_RTL8366RB ++ select I2C_GPIO + select REGMAP_I2C + help + Select to enable support for registering switches connected +diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c +index 01e0634ce999..fce1daac3557 100644 +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -31,10 +31,13 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -342,6 +345,117 @@ static struct i2c_driver realtek_smi_driver = { + }; + module_i2c_driver(realtek_smi_driver); + ++struct realtek_smi_plat_priv { ++ struct i2c_adapter adap; ++ struct i2c_algo_bit_data algo; ++ struct gpio_desc *sda, *scl; ++ struct i2c_client *client; ++}; ++ ++static void realtek_smi_setsda(void *data, int state) ++{ ++ struct realtek_smi_plat_priv *priv = data; ++ ++ gpiod_set_value_cansleep(priv->sda, state); ++} ++ ++static void realtek_smi_setscl(void *data, int state) ++{ ++ struct realtek_smi_plat_priv *priv = data; ++ ++ gpiod_set_value_cansleep(priv->scl, state); ++} ++ ++static int realtek_smi_getsda(void *data) ++{ ++ struct realtek_smi_plat_priv *priv = data; ++ ++ return gpiod_get_value_cansleep(priv->sda); ++} ++ ++static int realtek_smi_getscl(void *data) ++{ ++ struct realtek_smi_plat_priv *priv = data; ++ ++ return gpiod_get_value_cansleep(priv->scl); ++} ++ ++static int realtek_smi_plat_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *match; ++ const struct realtek_variant *var; ++ struct device *dev = &pdev->dev; ++ struct realtek_smi_plat_priv *priv; ++ struct i2c_board_info binfo; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, priv); ++ ++ match = of_match_device(dev->driver->of_match_table, dev); ++ var = match->data; ++ ++ /* Fetch SMI pins */ ++ priv->sda = devm_gpiod_get(dev, "mdio", GPIOD_OUT_HIGH_OPEN_DRAIN); ++ if (IS_ERR(priv->sda)) ++ return PTR_ERR(priv->sda); ++ priv->scl = devm_gpiod_get(dev, "mdc", GPIOD_OUT_HIGH_OPEN_DRAIN); ++ if (IS_ERR(priv->scl)) ++ return PTR_ERR(priv->scl); ++ ++ /* Initialize I2C adapter */ ++ strscpy(priv->adap.name, dev_name(dev), sizeof(priv->adap.name)); ++ priv->adap.owner = THIS_MODULE; ++ priv->adap.algo_data = &priv->algo; ++ priv->adap.dev.parent = dev; ++ priv->algo.setsda = realtek_smi_setsda; ++ priv->algo.setscl = realtek_smi_setscl; ++ priv->algo.getsda = realtek_smi_getsda; ++ priv->algo.getscl = realtek_smi_getscl; ++ priv->algo.udelay = var->clk_delay; ++ priv->algo.timeout = HZ / 10; /* 100 ms */ ++ priv->algo.data = priv; ++ ++ ret = i2c_bit_add_bus(&priv->adap); ++ if (ret) { ++ dev_err(dev, "Failed to create I2C adapter\n"); ++ return ret; ++ } ++ ++ memset(&binfo, 0, sizeof(binfo)); ++ strscpy(binfo.type, match->compatible, I2C_NAME_SIZE); ++ binfo.addr = var->i2c_addr; ++ binfo.of_node = dev->of_node; ++ ++ priv->client = i2c_new_client_device(&priv->adap, &binfo); ++ if (IS_ERR(priv->client)) { ++ dev_err(dev, "Failed to create I2C device\n"); ++ return PTR_ERR(priv->client); ++ } ++ ++ return 0; ++} ++ ++static void realtek_smi_plat_remove(struct platform_device *pdev) ++{ ++ struct realtek_smi_plat_priv *priv = platform_get_drvdata(pdev); ++ ++ i2c_unregister_device(priv->client); ++ i2c_del_adapter(&priv->adap); ++} ++ ++static struct platform_driver realtek_smi_plat_driver = { ++ .driver = { ++ .name = "realtek-smi", ++ .of_match_table = realtek_smi_of_match, ++ }, ++ .probe = realtek_smi_plat_probe, ++ .remove_new = realtek_smi_plat_remove, ++}; ++module_platform_driver(realtek_smi_plat_driver); ++ + MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface"); + MODULE_LICENSE("GPL"); +-- +2.43.2 + + +From e2474c1d276b790b55b9518df4e0f1959221db65 Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Thu, 21 Mar 2024 16:39:46 -0600 +Subject: [PATCH 09/11] local: begin improving tagging decoder + +--- + net/dsa/tag_rtl8_4.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/net/dsa/tag_rtl8_4.c b/net/dsa/tag_rtl8_4.c +index 4f67834fd121..f9181cff5f0e 100644 +--- a/net/dsa/tag_rtl8_4.c ++++ b/net/dsa/tag_rtl8_4.c +@@ -35,8 +35,13 @@ + * X | reserved + * ------------+------------- + * REASON | reason for forwarding packet to CPU +- * | 0: packet was forwarded or flooded to CPU +- * | 80: packet was trapped to CPU ++ * | 0x00: packet was forwarded or flooded to CPU ++ * | 0x41: dot1x unauthorized ++ * | 0x4B: port learning limit exceeded ++ * | 0x50: unknown unicast destination MAC ++ * | 0x51: unknown multicast destination MAC ++ * | 0x54: unknown source MAC ++ * | 0x55: unmatched source MAC + * FID_EN | 1: packet has an FID + * | 0: no FID + * FID | FID of packet (if FID_EN=1) +@@ -92,8 +97,13 @@ + #define RTL8_4_PROTOCOL GENMASK(15, 8) + #define RTL8_4_PROTOCOL_RTL8365MB 0x04 + #define RTL8_4_REASON GENMASK(7, 0) +-#define RTL8_4_REASON_FORWARD 0 +-#define RTL8_4_REASON_TRAP 80 ++#define RTL8_4_REASON_FORWARD 0x00 ++#define RTL8_4_REASON_1XUNAUTH 0x41 ++#define RTL8_4_REASON_LUT_OVER 0x4B ++#define RTL8_4_REASON_UNK_UNICAST 0x50 ++#define RTL8_4_REASON_UNK_MULTICAST 0x51 ++#define RTL8_4_REASON_UNK_SOURCE 0x54 ++#define RTL8_4_REASON_UNMATCH_SOURCE 0x55 + + #define RTL8_4_LEARN_DIS BIT(5) + +@@ -188,7 +198,7 @@ static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev, + return -ENOENT; + } + +- if (reason != RTL8_4_REASON_TRAP) ++ if (reason == RTL8_4_REASON_FORWARD) + dsa_default_offload_fwd_mark(skb); + + return 0; +-- +2.43.2 + + +From b7c86d836c03ba9a8254d564697792612aed9e90 Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Thu, 21 Mar 2024 19:10:46 -0600 +Subject: [PATCH 10/11] local: realtek: trap standalone ports rather than use + the isolation matrix + +--- + drivers/net/dsa/realtek/rtl8365mb.c | 63 +++++++++++++++++++++++++++-- + 1 file changed, 59 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index b723ade207c9..d4f0374d9dac 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -281,6 +281,18 @@ + (RTL8365MB_PORT_ISOLATION_REG_BASE + (_physport)) + #define RTL8365MB_PORT_ISOLATION_MASK 0x07FF + ++/* Dot1x registers; to put ports in UNAUTH mode so they trap on ingress */ ++#define RTL8365MB_DOT1X_PORT_ENABLE_REG 0x0A80 ++#define RTL8365MB_DOT1X_PORT_AUTH_REG 0x0A82 ++#define RTL8365MB_DOT1X_PORT_OPDIR_REG 0x0A83 ++#define RTL8365MB_DOT1X_UNAUTH_ACT_BASE 0x0A84 ++#define RTL8365MB_DOT1X_UNAUTH_ACT_REG(_physport) \ ++ (RTL8365MB_DOT1X_UNAUTH_ACT_BASE + ((_physport) >> 3)) ++#define RTL8365MB_DOT1X_UNAUTH_ACT_OFFSET(_physport) \ ++ (((_physport) & 0x7) << 1) ++#define RTL8365MB_DOT1X_UNAUTH_ACT_MASK(_physport) \ ++ (0x3 << RTL8365MB_DOT1X_UNAUTH_ACT_OFFSET((_physport))) ++ + /* MSTP port state registers - indexed by tree instance */ + #define RTL8365MB_MSTI_CTRL_BASE 0x0A00 + #define RTL8365MB_MSTI_CTRL_REG(_msti, _physport) \ +@@ -597,6 +609,12 @@ enum rtl8365mb_cpu_rxlen { + RTL8365MB_CPU_RXLEN_64BYTES = 1, + }; + ++enum rtl8365mb_dot1x_action { ++ RTL8365MB_DOT1X_ACTION_DROP = 0, ++ RTL8365MB_DOT1X_ACTION_TRAP = 1, ++ RTL8365MB_DOT1X_ACTION_VLAN = 2, ++}; ++ + /** + * struct rtl8365mb_cpu - CPU port configuration + * @enable: enable/disable hardware insertion of CPU tag in switch->CPU frames +@@ -1228,6 +1246,43 @@ static int rtl8365mb_port_set_isolation(struct realtek_priv *priv, int port, + return regmap_write(priv->map, RTL8365MB_PORT_ISOLATION_REG(port), mask); + } + ++static int rtl8365mb_port_set_trapping(struct realtek_priv *priv, int port, ++ bool enable) ++{ ++ int ret; ++ ++ /* Prevent ingress traffic from being handled by the switch fabric by ++ * using dot1x mode. The dot1x functionality isn't used elsewhere in ++ * the driver, so is a convenient method for trapping ingress traffic. ++ */ ++ ++ ret = regmap_update_bits(priv->map, RTL8365MB_DOT1X_PORT_ENABLE_REG, ++ BIT(port), enable ? BIT(port) : 0); ++ if (ret) ++ return ret; ++ ++ if (!enable) ++ return 0; ++ ++ ret = regmap_update_bits(priv->map, RTL8365MB_DOT1X_PORT_AUTH_REG, ++ BIT(port), 0); ++ if (ret) ++ return ret; ++ ++ /* Match on input only */ ++ ret = regmap_update_bits(priv->map, RTL8365MB_DOT1X_PORT_OPDIR_REG, ++ BIT(port), BIT(port)); ++ if (ret) ++ return ret; ++ ++ /* Set action to TRAP */ ++ return regmap_update_bits(priv->map, ++ RTL8365MB_DOT1X_UNAUTH_ACT_REG(port), ++ RTL8365MB_DOT1X_UNAUTH_ACT_MASK(port), ++ RTL8365MB_DOT1X_ACTION_TRAP << ++ RTL8365MB_DOT1X_UNAUTH_ACT_OFFSET(port)); ++} ++ + static int rtl8365mb_mib_counter_read(struct realtek_priv *priv, int port, + u32 offset, u32 length, u64 *mibvalue) + { +@@ -2003,13 +2058,13 @@ static int rtl8365mb_setup(struct dsa_switch *ds) + if (dsa_is_unused_port(priv->ds, i)) + continue; + +- /* Forward only to the CPU */ +- ret = rtl8365mb_port_set_isolation(priv, i, cpu->mask); ++ /* Clear the port's isolation mask */ ++ ret = rtl8365mb_port_set_isolation(priv, i, 0); + if (ret) + goto out_teardown_irq; + +- /* Disable learning */ +- ret = rtl8365mb_port_set_learning(priv, i, false); ++ /* Trap all ingress traffic on this port */ ++ ret = rtl8365mb_port_set_trapping(priv, i, true); + if (ret) + goto out_teardown_irq; + +-- +2.43.2 + + +From e88bfa1bf5804123596c625c5bb18b40e60c2246 Mon Sep 17 00:00:00 2001 +From: Sam Edwards +Date: Fri, 22 Mar 2024 17:43:16 -0600 +Subject: [PATCH 11/11] local: realtek: implement bridge offload + +--- + drivers/net/dsa/realtek/rtl8365mb.c | 80 +++++++++++++++++++++++++++++ + 1 file changed, 80 insertions(+) + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index d4f0374d9dac..61f8dac3c914 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -275,6 +275,15 @@ + #define RTL8365MB_LUT_PORT_LEARN_LIMIT_REG(_physport) \ + (RTL8365MB_LUT_PORT_LEARN_LIMIT_BASE + (_physport)) + ++/* Port-based EFID registers */ ++#define RTL8365MB_PORT_EFID_BASE 0x0A32 ++#define RTL8365MB_PORT_EFID_REG(_physport) \ ++ (RTL8365MB_PORT_EFID_BASE + ((_physport) >> 2)) ++#define RTL8365MB_PORT_EFID_OFFSET(_physport) \ ++ (((_physport) & 0x3) << 2) ++#define RTL8365MB_PORT_EFID_MASK(_physport) \ ++ (0x7 << RTL8365MB_PORT_EFID_OFFSET((_physport))) ++ + /* Port isolation (forwarding mask) registers */ + #define RTL8365MB_PORT_ISOLATION_REG_BASE 0x08A2 + #define RTL8365MB_PORT_ISOLATION_REG(_physport) \ +@@ -1283,6 +1292,70 @@ static int rtl8365mb_port_set_trapping(struct realtek_priv *priv, int port, + RTL8365MB_DOT1X_UNAUTH_ACT_OFFSET(port)); + } + ++static int rtl8365mb_port_set_efid(struct realtek_priv *priv, int port, u8 efid) ++{ ++ return regmap_update_bits(priv->map, RTL8365MB_PORT_EFID_REG(port), ++ RTL8365MB_PORT_EFID_MASK(port), ++ efid << RTL8365MB_PORT_EFID_OFFSET(port)); ++} ++ ++static int rtl8365mb_bridge_apply_isolation(struct realtek_priv *priv, ++ const struct dsa_bridge *bridge) ++{ ++ struct rtl8365mb *mb = (struct rtl8365mb *)priv->chip_data; ++ struct rtl8365mb_cpu *cpu = &mb->cpu; ++ unsigned long cpu_mask = cpu->mask; ++ unsigned long bridge_mask; ++ int ret; ++ int port; ++ ++ /* Make sure the CPU is included in every bridge */ ++ bridge_mask = cpu_mask; ++ ++ for (int i = 0; i < priv->num_ports; i++) { ++ if (dsa_port_offloads_bridge(dsa_to_port(priv->ds, i), bridge)) ++ bridge_mask |= BIT(i); ++ } ++ ++ /* Don't set the CPU port's isolation; it's bypassed anyway */ ++ for_each_andnot_bit(port, &bridge_mask, &cpu_mask, priv->num_ports) { ++ ret = rtl8365mb_port_set_isolation(priv, port, bridge_mask); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rtl8365mb_port_bridge_join(struct dsa_switch *ds, int port, ++ struct dsa_bridge bridge, ++ bool *tx_fwd_offload, ++ struct netlink_ext_ack *extack) ++{ ++ struct realtek_priv *priv = ds->priv; ++ u8 efid = bridge.num; ++ int ret; ++ ++ ret = rtl8365mb_port_set_efid(priv, port, efid); ++ if (ret) ++ return ret; ++ ++ ret = rtl8365mb_bridge_apply_isolation(priv, &bridge); ++ if (ret) ++ return ret; ++ ++ return rtl8365mb_port_set_trapping(priv, port, false); ++} ++ ++static void rtl8365mb_port_bridge_leave(struct dsa_switch *ds, int port, ++ struct dsa_bridge bridge) ++{ ++ struct realtek_priv *priv = ds->priv; ++ ++ rtl8365mb_port_set_trapping(priv, port, true); ++ rtl8365mb_bridge_apply_isolation(priv, &bridge); ++} ++ + static int rtl8365mb_mib_counter_read(struct realtek_priv *priv, int port, + u32 offset, u32 length, u64 *mibvalue) + { +@@ -2016,6 +2089,9 @@ static int rtl8365mb_setup(struct dsa_switch *ds) + int ret; + int i; + ++ ds->fdb_isolation = true; ++ ds->max_num_bridges = 7; ++ + mb = (struct rtl8365mb *)priv->chip_data; + cpu = &mb->cpu; + +@@ -2201,6 +2277,8 @@ static const struct dsa_switch_ops rtl8365mb_switch_ops_smi = { + .get_stats64 = rtl8365mb_get_stats64, + .port_change_mtu = rtl8365mb_port_change_mtu, + .port_max_mtu = rtl8365mb_port_max_mtu, ++ .port_bridge_join = rtl8365mb_port_bridge_join, ++ .port_bridge_leave = rtl8365mb_port_bridge_leave, + }; + + static const struct dsa_switch_ops rtl8365mb_switch_ops_mdio = { +@@ -2224,6 +2302,8 @@ static const struct dsa_switch_ops rtl8365mb_switch_ops_mdio = { + .get_stats64 = rtl8365mb_get_stats64, + .port_change_mtu = rtl8365mb_port_change_mtu, + .port_max_mtu = rtl8365mb_port_max_mtu, ++ .port_bridge_join = rtl8365mb_port_bridge_join, ++ .port_bridge_leave = rtl8365mb_port_bridge_leave, + }; + + static const struct realtek_ops rtl8365mb_ops = { +-- +2.43.2 +