Merge branch 'net-dsa-yt921x-add-support-for-motorcomm-yt921x'

David Yang says:

====================
net: dsa: yt921x: Add support for Motorcomm YT921x

Motorcomm YT921x is a series of ethernet switches developed by Shanghai
Motorcomm Electronic Technology, including:

  - YT9215S / YT9215RB / YT9215SC: 5 GbE phys
  - YT9213NB / YT9214NB: 2 GbE phys
  - YT9218N / YT9218MB: 8 GbE phys

and up to 2 serdes interfaces.

This patch adds basic support for a working DSA switch.
====================

Link: https://patch.msgid.link/20251017060859.326450-1-mmyangfl@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-10-21 18:25:35 -07:00
11 changed files with 3729 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/dsa/motorcomm,yt921x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Motorcomm YT921x Ethernet switch family
maintainers:
- David Yang <mmyangfl@gmail.com>
description: |
The Motorcomm YT921x series is a family of Ethernet switches with up to 8
internal GbE PHYs and up to 2 GMACs, including:
- YT9215S / YT9215RB / YT9215SC: 5 GbE PHYs (Port 0-4) + 2 GMACs (Port 8-9)
- YT9213NB: 2 GbE PHYs (Port 1/3) + 1 GMAC (Port 9)
- YT9214NB: 2 GbE PHYs (Port 1/3) + 2 GMACs (Port 8-9)
- YT9218N: 8 GbE PHYs (Port 0-7)
- YT9218MB: 8 GbE PHYs (Port 0-7) + 2 GMACs (Port 8-9)
Any port can be used as the CPU port.
properties:
compatible:
const: motorcomm,yt9215
reg:
enum: [0x0, 0x1d]
reset-gpios:
maxItems: 1
mdio:
$ref: /schemas/net/mdio.yaml#
unevaluatedProperties: false
description:
Internal MDIO bus for the internal GbE PHYs. PHY 0-7 are used for Port
0-7 respectively.
mdio-external:
$ref: /schemas/net/mdio.yaml#
unevaluatedProperties: false
description:
External MDIO bus to access external components. External PHYs for GMACs
(Port 8-9) are expected to be connected to the external MDIO bus in
vendor's reference design, but that is not a hard limitation from the
chip.
required:
- compatible
- reg
allOf:
- $ref: dsa.yaml#/$defs/ethernet-ports
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
mdio {
#address-cells = <1>;
#size-cells = <0>;
switch@1d {
compatible = "motorcomm,yt9215";
/* default 0x1d, alternate 0x0 */
reg = <0x1d>;
reset-gpios = <&tlmm 39 GPIO_ACTIVE_LOW>;
mdio {
#address-cells = <1>;
#size-cells = <0>;
sw_phy0: phy@0 {
reg = <0x0>;
};
sw_phy1: phy@1 {
reg = <0x1>;
};
sw_phy2: phy@2 {
reg = <0x2>;
};
sw_phy3: phy@3 {
reg = <0x3>;
};
sw_phy4: phy@4 {
reg = <0x4>;
};
};
mdio-external {
#address-cells = <1>;
#size-cells = <0>;
phy1: phy@b {
reg = <0xb>;
};
};
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
ethernet-port@0 {
reg = <0>;
label = "lan1";
phy-mode = "internal";
phy-handle = <&sw_phy0>;
};
ethernet-port@1 {
reg = <1>;
label = "lan2";
phy-mode = "internal";
phy-handle = <&sw_phy1>;
};
ethernet-port@2 {
reg = <2>;
label = "lan3";
phy-mode = "internal";
phy-handle = <&sw_phy2>;
};
ethernet-port@3 {
reg = <3>;
label = "lan4";
phy-mode = "internal";
phy-handle = <&sw_phy3>;
};
ethernet-port@4 {
reg = <4>;
label = "lan5";
phy-mode = "internal";
phy-handle = <&sw_phy4>;
};
/* CPU port */
ethernet-port@8 {
reg = <8>;
phy-mode = "2500base-x";
ethernet = <&eth0>;
fixed-link {
speed = <2500>;
full-duplex;
};
};
/* if external phy is connected to a MAC */
ethernet-port@9 {
reg = <9>;
label = "wan";
phy-mode = "rgmii-id";
phy-handle = <&phy1>;
};
};
};
};

View File

@@ -17435,6 +17435,14 @@ S: Maintained
F: Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml
F: drivers/net/phy/motorcomm.c
MOTORCOMM YT921X ETHERNET SWITCH DRIVER
M: David Yang <mmyangfl@gmail.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml
F: drivers/net/dsa/yt921x.*
F: net/dsa/tag_yt921x.c
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
M: Jiri Slaby <jirislaby@kernel.org>
S: Maintained

View File

@@ -154,4 +154,11 @@ config NET_DSA_VITESSE_VSC73XX_PLATFORM
This enables support for the Vitesse VSC7385, VSC7388, VSC7395
and VSC7398 SparX integrated ethernet switches, connected over
a CPU-attached address bus and work in memory-mapped I/O mode.
config NET_DSA_YT921X
tristate "Motorcomm YT9215 ethernet switch chip support"
select NET_DSA_TAG_YT921X
help
This enables support for the Motorcomm YT9215 ethernet switch
chip.
endmenu

View File

@@ -14,6 +14,7 @@ obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
obj-y += b53/
obj-y += hirschmann/
obj-y += lantiq/

2891
drivers/net/dsa/yt921x.c Normal file

File diff suppressed because it is too large Load Diff

504
drivers/net/dsa/yt921x.h Normal file
View File

@@ -0,0 +1,504 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2025 David Yang
*/
#ifndef __YT921X_H
#define __YT921X_H
#include <net/dsa.h>
#define YT921X_SMI_SWITCHID_M GENMASK(3, 2)
#define YT921X_SMI_SWITCHID(x) FIELD_PREP(YT921X_SMI_SWITCHID_M, (x))
#define YT921X_SMI_AD BIT(1)
#define YT921X_SMI_ADDR 0
#define YT921X_SMI_DATA YT921X_SMI_AD
#define YT921X_SMI_RW BIT(0)
#define YT921X_SMI_WRITE 0
#define YT921X_SMI_READ YT921X_SMI_RW
#define YT921X_SWITCHID_NUM 4
#define YT921X_RST 0x80000
#define YT921X_RST_HW BIT(31)
#define YT921X_RST_SW BIT(1)
#define YT921X_FUNC 0x80004
#define YT921X_FUNC_MIB BIT(1)
#define YT921X_CHIP_ID 0x80008
#define YT921X_CHIP_ID_MAJOR GENMASK(31, 16)
#define YT921X_EXT_CPU_PORT 0x8000c
#define YT921X_EXT_CPU_PORT_TAG_EN BIT(15)
#define YT921X_EXT_CPU_PORT_PORT_EN BIT(14)
#define YT921X_EXT_CPU_PORT_PORT_M GENMASK(3, 0)
#define YT921X_EXT_CPU_PORT_PORT(x) FIELD_PREP(YT921X_EXT_CPU_PORT_PORT_M, (x))
#define YT921X_CPU_TAG_TPID 0x80010
#define YT921X_CPU_TAG_TPID_TPID_M GENMASK(15, 0)
/* Same as ETH_P_YT921X, but this represents the true HW default, while the
* former is a local convention chosen by us.
*/
#define YT921X_CPU_TAG_TPID_TPID_DEFAULT 0x9988
#define YT921X_PVID_SEL 0x80014
#define YT921X_PVID_SEL_SVID_PORTn(port) BIT(port)
#define YT921X_SERDES_CTRL 0x80028
#define YT921X_SERDES_CTRL_PORTn_TEST(port) BIT((port) - 3)
#define YT921X_SERDES_CTRL_PORTn(port) BIT((port) - 8)
#define YT921X_IO_LEVEL 0x80030
#define YT9215_IO_LEVEL_NORMAL_M GENMASK(5, 4)
#define YT9215_IO_LEVEL_NORMAL(x) FIELD_PREP(YT9215_IO_LEVEL_NORMAL_M, (x))
#define YT9215_IO_LEVEL_NORMAL_3V3 YT9215_IO_LEVEL_NORMAL(0)
#define YT9215_IO_LEVEL_NORMAL_1V8 YT9215_IO_LEVEL_NORMAL(3)
#define YT9215_IO_LEVEL_RGMII1_M GENMASK(3, 2)
#define YT9215_IO_LEVEL_RGMII1(x) FIELD_PREP(YT9215_IO_LEVEL_RGMII1_M, (x))
#define YT9215_IO_LEVEL_RGMII1_3V3 YT9215_IO_LEVEL_RGMII1(0)
#define YT9215_IO_LEVEL_RGMII1_2V5 YT9215_IO_LEVEL_RGMII1(1)
#define YT9215_IO_LEVEL_RGMII1_1V8 YT9215_IO_LEVEL_RGMII1(2)
#define YT9215_IO_LEVEL_RGMII0_M GENMASK(1, 0)
#define YT9215_IO_LEVEL_RGMII0(x) FIELD_PREP(YT9215_IO_LEVEL_RGMII0_M, (x))
#define YT9215_IO_LEVEL_RGMII0_3V3 YT9215_IO_LEVEL_RGMII0(0)
#define YT9215_IO_LEVEL_RGMII0_2V5 YT9215_IO_LEVEL_RGMII0(1)
#define YT9215_IO_LEVEL_RGMII0_1V8 YT9215_IO_LEVEL_RGMII0(2)
#define YT9218_IO_LEVEL_RGMII1_M GENMASK(5, 4)
#define YT9218_IO_LEVEL_RGMII1(x) FIELD_PREP(YT9218_IO_LEVEL_RGMII1_M, (x))
#define YT9218_IO_LEVEL_RGMII1_3V3 YT9218_IO_LEVEL_RGMII1(0)
#define YT9218_IO_LEVEL_RGMII1_2V5 YT9218_IO_LEVEL_RGMII1(1)
#define YT9218_IO_LEVEL_RGMII1_1V8 YT9218_IO_LEVEL_RGMII1(2)
#define YT9218_IO_LEVEL_RGMII0_M GENMASK(3, 2)
#define YT9218_IO_LEVEL_RGMII0(x) FIELD_PREP(YT9218_IO_LEVEL_RGMII0_M, (x))
#define YT9218_IO_LEVEL_RGMII0_3V3 YT9218_IO_LEVEL_RGMII0(0)
#define YT9218_IO_LEVEL_RGMII0_2V5 YT9218_IO_LEVEL_RGMII0(1)
#define YT9218_IO_LEVEL_RGMII0_1V8 YT9218_IO_LEVEL_RGMII0(2)
#define YT9218_IO_LEVEL_NORMAL_M GENMASK(1, 0)
#define YT9218_IO_LEVEL_NORMAL(x) FIELD_PREP(YT9218_IO_LEVEL_NORMAL_M, (x))
#define YT9218_IO_LEVEL_NORMAL_3V3 YT9218_IO_LEVEL_NORMAL(0)
#define YT9218_IO_LEVEL_NORMAL_1V8 YT9218_IO_LEVEL_NORMAL(3)
#define YT921X_MAC_ADDR_HI2 0x80080
#define YT921X_MAC_ADDR_LO4 0x80084
#define YT921X_SERDESn(port) (0x8008c + 4 * ((port) - 8))
#define YT921X_SERDES_MODE_M GENMASK(9, 7)
#define YT921X_SERDES_MODE(x) FIELD_PREP(YT921X_SERDES_MODE_M, (x))
#define YT921X_SERDES_MODE_SGMII YT921X_SERDES_MODE(0)
#define YT921X_SERDES_MODE_REVSGMII YT921X_SERDES_MODE(1)
#define YT921X_SERDES_MODE_1000BASEX YT921X_SERDES_MODE(2)
#define YT921X_SERDES_MODE_100BASEX YT921X_SERDES_MODE(3)
#define YT921X_SERDES_MODE_2500BASEX YT921X_SERDES_MODE(4)
#define YT921X_SERDES_RX_PAUSE BIT(6)
#define YT921X_SERDES_TX_PAUSE BIT(5)
#define YT921X_SERDES_LINK BIT(4) /* force link */
#define YT921X_SERDES_DUPLEX_FULL BIT(3)
#define YT921X_SERDES_SPEED_M GENMASK(2, 0)
#define YT921X_SERDES_SPEED(x) FIELD_PREP(YT921X_SERDES_SPEED_M, (x))
#define YT921X_SERDES_SPEED_10 YT921X_SERDES_SPEED(0)
#define YT921X_SERDES_SPEED_100 YT921X_SERDES_SPEED(1)
#define YT921X_SERDES_SPEED_1000 YT921X_SERDES_SPEED(2)
#define YT921X_SERDES_SPEED_10000 YT921X_SERDES_SPEED(3)
#define YT921X_SERDES_SPEED_2500 YT921X_SERDES_SPEED(4)
#define YT921X_PORTn_CTRL(port) (0x80100 + 4 * (port))
#define YT921X_PORT_CTRL_PAUSE_AN BIT(10)
#define YT921X_PORTn_STATUS(port) (0x80200 + 4 * (port))
#define YT921X_PORT_LINK BIT(9) /* CTRL: auto negotiation */
#define YT921X_PORT_HALF_PAUSE BIT(8) /* Half-duplex back pressure mode */
#define YT921X_PORT_DUPLEX_FULL BIT(7)
#define YT921X_PORT_RX_PAUSE BIT(6)
#define YT921X_PORT_TX_PAUSE BIT(5)
#define YT921X_PORT_RX_MAC_EN BIT(4)
#define YT921X_PORT_TX_MAC_EN BIT(3)
#define YT921X_PORT_SPEED_M GENMASK(2, 0)
#define YT921X_PORT_SPEED(x) FIELD_PREP(YT921X_PORT_SPEED_M, (x))
#define YT921X_PORT_SPEED_10 YT921X_PORT_SPEED(0)
#define YT921X_PORT_SPEED_100 YT921X_PORT_SPEED(1)
#define YT921X_PORT_SPEED_1000 YT921X_PORT_SPEED(2)
#define YT921X_PORT_SPEED_10000 YT921X_PORT_SPEED(3)
#define YT921X_PORT_SPEED_2500 YT921X_PORT_SPEED(4)
#define YT921X_PON_STRAP_FUNC 0x80320
#define YT921X_PON_STRAP_VAL 0x80324
#define YT921X_PON_STRAP_CAP 0x80328
#define YT921X_PON_STRAP_EEE BIT(16)
#define YT921X_PON_STRAP_LOOP_DETECT BIT(7)
#define YT921X_MDIO_POLLINGn(port) (0x80364 + 4 * ((port) - 8))
#define YT921X_MDIO_POLLING_DUPLEX_FULL BIT(4)
#define YT921X_MDIO_POLLING_LINK BIT(3)
#define YT921X_MDIO_POLLING_SPEED_M GENMASK(2, 0)
#define YT921X_MDIO_POLLING_SPEED(x) FIELD_PREP(YT921X_MDIO_POLLING_SPEED_M, (x))
#define YT921X_MDIO_POLLING_SPEED_10 YT921X_MDIO_POLLING_SPEED(0)
#define YT921X_MDIO_POLLING_SPEED_100 YT921X_MDIO_POLLING_SPEED(1)
#define YT921X_MDIO_POLLING_SPEED_1000 YT921X_MDIO_POLLING_SPEED(2)
#define YT921X_MDIO_POLLING_SPEED_10000 YT921X_MDIO_POLLING_SPEED(3)
#define YT921X_MDIO_POLLING_SPEED_2500 YT921X_MDIO_POLLING_SPEED(4)
#define YT921X_SENSOR 0x8036c
#define YT921X_SENSOR_TEMP BIT(18)
#define YT921X_TEMP 0x80374
#define YT921X_CHIP_MODE 0x80388
#define YT921X_CHIP_MODE_MODE GENMASK(1, 0)
#define YT921X_XMII_CTRL 0x80394
#define YT921X_XMII_CTRL_PORTn(port) BIT(9 - (port)) /* Yes, it's reversed */
#define YT921X_XMIIn(port) (0x80400 + 8 * ((port) - 8))
#define YT921X_XMII_MODE_M GENMASK(31, 29)
#define YT921X_XMII_MODE(x) FIELD_PREP(YT921X_XMII_MODE_M, (x))
#define YT921X_XMII_MODE_MII YT921X_XMII_MODE(0)
#define YT921X_XMII_MODE_REVMII YT921X_XMII_MODE(1)
#define YT921X_XMII_MODE_RMII YT921X_XMII_MODE(2)
#define YT921X_XMII_MODE_REVRMII YT921X_XMII_MODE(3)
#define YT921X_XMII_MODE_RGMII YT921X_XMII_MODE(4)
#define YT921X_XMII_MODE_DISABLE YT921X_XMII_MODE(5)
#define YT921X_XMII_LINK BIT(19) /* force link */
#define YT921X_XMII_EN BIT(18)
#define YT921X_XMII_SOFT_RST BIT(17)
#define YT921X_XMII_RGMII_TX_DELAY_150PS_M GENMASK(16, 13)
#define YT921X_XMII_RGMII_TX_DELAY_150PS(x) FIELD_PREP(YT921X_XMII_RGMII_TX_DELAY_150PS_M, (x))
#define YT921X_XMII_TX_CLK_IN BIT(11)
#define YT921X_XMII_RX_CLK_IN BIT(10)
#define YT921X_XMII_RGMII_TX_DELAY_2NS BIT(8)
#define YT921X_XMII_RGMII_TX_CLK_OUT BIT(7)
#define YT921X_XMII_RGMII_RX_DELAY_150PS_M GENMASK(6, 3)
#define YT921X_XMII_RGMII_RX_DELAY_150PS(x) FIELD_PREP(YT921X_XMII_RGMII_RX_DELAY_150PS_M, (x))
#define YT921X_XMII_RMII_PHY_TX_CLK_OUT BIT(2)
#define YT921X_XMII_REVMII_TX_CLK_OUT BIT(1)
#define YT921X_XMII_REVMII_RX_CLK_OUT BIT(0)
#define YT921X_MACn_FRAME(port) (0x81008 + 0x1000 * (port))
#define YT921X_MAC_FRAME_SIZE_M GENMASK(21, 8)
#define YT921X_MAC_FRAME_SIZE(x) FIELD_PREP(YT921X_MAC_FRAME_SIZE_M, (x))
#define YT921X_EEEn_VAL(port) (0xa0000 + 0x40 * (port))
#define YT921X_EEE_VAL_DATA BIT(1)
#define YT921X_EEE_CTRL 0xb0000
#define YT921X_EEE_CTRL_ENn(port) BIT(port)
#define YT921X_MIB_CTRL 0xc0004
#define YT921X_MIB_CTRL_CLEAN BIT(30)
#define YT921X_MIB_CTRL_PORT_M GENMASK(6, 3)
#define YT921X_MIB_CTRL_PORT(x) FIELD_PREP(YT921X_MIB_CTRL_PORT_M, (x))
#define YT921X_MIB_CTRL_ONE_PORT BIT(1)
#define YT921X_MIB_CTRL_ALL_PORT BIT(0)
#define YT921X_MIBn_DATA0(port) (0xc0100 + 0x100 * (port))
#define YT921X_MIBn_DATAm(port, x) (YT921X_MIBn_DATA0(port) + 4 * (x))
#define YT921X_EDATA_CTRL 0xe0000
#define YT921X_EDATA_CTRL_ADDR_M GENMASK(15, 8)
#define YT921X_EDATA_CTRL_ADDR(x) FIELD_PREP(YT921X_EDATA_CTRL_ADDR_M, (x))
#define YT921X_EDATA_CTRL_OP_M GENMASK(3, 0)
#define YT921X_EDATA_CTRL_OP(x) FIELD_PREP(YT921X_EDATA_CTRL_OP_M, (x))
#define YT921X_EDATA_CTRL_READ YT921X_EDATA_CTRL_OP(5)
#define YT921X_EDATA_DATA 0xe0004
#define YT921X_EDATA_DATA_DATA_M GENMASK(31, 24)
#define YT921X_EDATA_DATA_STATUS_M GENMASK(3, 0)
#define YT921X_EDATA_DATA_STATUS(x) FIELD_PREP(YT921X_EDATA_DATA_STATUS_M, (x))
#define YT921X_EDATA_DATA_IDLE YT921X_EDATA_DATA_STATUS(3)
#define YT921X_EXT_MBUS_OP 0x6a000
#define YT921X_INT_MBUS_OP 0xf0000
#define YT921X_MBUS_OP_START BIT(0)
#define YT921X_EXT_MBUS_CTRL 0x6a004
#define YT921X_INT_MBUS_CTRL 0xf0004
#define YT921X_MBUS_CTRL_PORT_M GENMASK(25, 21)
#define YT921X_MBUS_CTRL_PORT(x) FIELD_PREP(YT921X_MBUS_CTRL_PORT_M, (x))
#define YT921X_MBUS_CTRL_REG_M GENMASK(20, 16)
#define YT921X_MBUS_CTRL_REG(x) FIELD_PREP(YT921X_MBUS_CTRL_REG_M, (x))
#define YT921X_MBUS_CTRL_TYPE_M GENMASK(11, 8) /* wild guess */
#define YT921X_MBUS_CTRL_TYPE(x) FIELD_PREP(YT921X_MBUS_CTRL_TYPE_M, (x))
#define YT921X_MBUS_CTRL_TYPE_C22 YT921X_MBUS_CTRL_TYPE(4)
#define YT921X_MBUS_CTRL_OP_M GENMASK(3, 2) /* wild guess */
#define YT921X_MBUS_CTRL_OP(x) FIELD_PREP(YT921X_MBUS_CTRL_OP_M, (x))
#define YT921X_MBUS_CTRL_WRITE YT921X_MBUS_CTRL_OP(1)
#define YT921X_MBUS_CTRL_READ YT921X_MBUS_CTRL_OP(2)
#define YT921X_EXT_MBUS_DOUT 0x6a008
#define YT921X_INT_MBUS_DOUT 0xf0008
#define YT921X_EXT_MBUS_DIN 0x6a00c
#define YT921X_INT_MBUS_DIN 0xf000c
#define YT921X_PORTn_EGR(port) (0x100000 + 4 * (port))
#define YT921X_PORT_EGR_TPID_CTAG_M GENMASK(5, 4)
#define YT921X_PORT_EGR_TPID_CTAG(x) FIELD_PREP(YT921X_PORT_EGR_TPID_CTAG_M, (x))
#define YT921X_PORT_EGR_TPID_STAG_M GENMASK(3, 2)
#define YT921X_PORT_EGR_TPID_STAG(x) FIELD_PREP(YT921X_PORT_EGR_TPID_STAG_M, (x))
#define YT921X_TPID_EGRn(x) (0x100300 + 4 * (x)) /* [0, 3] */
#define YT921X_TPID_EGR_TPID_M GENMASK(15, 0)
#define YT921X_VLAN_IGR_FILTER 0x180280
#define YT921X_VLAN_IGR_FILTER_PORTn_BYPASS_IGMP(port) BIT((port) + 11)
#define YT921X_VLAN_IGR_FILTER_PORTn(port) BIT(port)
#define YT921X_PORTn_ISOLATION(port) (0x180294 + 4 * (port))
#define YT921X_PORT_ISOLATION_BLOCKn(port) BIT(port)
#define YT921X_PORTn_LEARN(port) (0x1803d0 + 4 * (port))
#define YT921X_PORT_LEARN_VID_LEARN_MULTI_EN BIT(22)
#define YT921X_PORT_LEARN_VID_LEARN_MODE BIT(21)
#define YT921X_PORT_LEARN_VID_LEARN_EN BIT(20)
#define YT921X_PORT_LEARN_SUSPEND_COPY_EN BIT(19)
#define YT921X_PORT_LEARN_SUSPEND_DROP_EN BIT(18)
#define YT921X_PORT_LEARN_DIS BIT(17)
#define YT921X_PORT_LEARN_LIMIT_EN BIT(16)
#define YT921X_PORT_LEARN_LIMIT_M GENMASK(15, 8)
#define YT921X_PORT_LEARN_LIMIT(x) FIELD_PREP(YT921X_PORT_LEARN_LIMIT_M, (x))
#define YT921X_PORT_LEARN_DROP_ON_EXCEEDED BIT(2)
#define YT921X_PORT_LEARN_MODE_M GENMASK(1, 0)
#define YT921X_PORT_LEARN_MODE(x) FIELD_PREP(YT921X_PORT_LEARN_MODE_M, (x))
#define YT921X_PORT_LEARN_MODE_AUTO YT921X_PORT_LEARN_MODE(0)
#define YT921X_PORT_LEARN_MODE_AUTO_AND_COPY YT921X_PORT_LEARN_MODE(1)
#define YT921X_PORT_LEARN_MODE_CPU_CONTROL YT921X_PORT_LEARN_MODE(2)
#define YT921X_AGEING 0x180440
#define YT921X_AGEING_INTERVAL_M GENMASK(15, 0)
#define YT921X_FDB_IN0 0x180454
#define YT921X_FDB_IN1 0x180458
#define YT921X_FDB_IN2 0x18045c
#define YT921X_FDB_OP 0x180460
#define YT921X_FDB_OP_INDEX_M GENMASK(22, 11)
#define YT921X_FDB_OP_INDEX(x) FIELD_PREP(YT921X_FDB_OP_INDEX_M, (x))
#define YT921X_FDB_OP_MODE_INDEX BIT(10) /* mac+fid / index */
#define YT921X_FDB_OP_FLUSH_MCAST BIT(9) /* ucast / mcast */
#define YT921X_FDB_OP_FLUSH_M GENMASK(8, 7)
#define YT921X_FDB_OP_FLUSH(x) FIELD_PREP(YT921X_FDB_OP_FLUSH_M, (x))
#define YT921X_FDB_OP_FLUSH_ALL YT921X_FDB_OP_FLUSH(0)
#define YT921X_FDB_OP_FLUSH_PORT YT921X_FDB_OP_FLUSH(1)
#define YT921X_FDB_OP_FLUSH_PORT_VID YT921X_FDB_OP_FLUSH(2)
#define YT921X_FDB_OP_FLUSH_VID YT921X_FDB_OP_FLUSH(3)
#define YT921X_FDB_OP_FLUSH_STATIC BIT(6)
#define YT921X_FDB_OP_NEXT_TYPE_M GENMASK(5, 4)
#define YT921X_FDB_OP_NEXT_TYPE(x) FIELD_PREP(YT921X_FDB_OP_NEXT_TYPE_M, (x))
#define YT921X_FDB_OP_NEXT_TYPE_UCAST_PORT YT921X_FDB_OP_NEXT_TYPE(0)
#define YT921X_FDB_OP_NEXT_TYPE_UCAST_VID YT921X_FDB_OP_NEXT_TYPE(1)
#define YT921X_FDB_OP_NEXT_TYPE_UCAST YT921X_FDB_OP_NEXT_TYPE(2)
#define YT921X_FDB_OP_NEXT_TYPE_MCAST YT921X_FDB_OP_NEXT_TYPE(3)
#define YT921X_FDB_OP_OP_M GENMASK(3, 1)
#define YT921X_FDB_OP_OP(x) FIELD_PREP(YT921X_FDB_OP_OP_M, (x))
#define YT921X_FDB_OP_OP_ADD YT921X_FDB_OP_OP(0)
#define YT921X_FDB_OP_OP_DEL YT921X_FDB_OP_OP(1)
#define YT921X_FDB_OP_OP_GET_ONE YT921X_FDB_OP_OP(2)
#define YT921X_FDB_OP_OP_GET_NEXT YT921X_FDB_OP_OP(3)
#define YT921X_FDB_OP_OP_FLUSH YT921X_FDB_OP_OP(4)
#define YT921X_FDB_OP_START BIT(0)
#define YT921X_FDB_RESULT 0x180464
#define YT921X_FDB_RESULT_DONE BIT(15)
#define YT921X_FDB_RESULT_NOTFOUND BIT(14)
#define YT921X_FDB_RESULT_OVERWRITED BIT(13)
#define YT921X_FDB_RESULT_INDEX_M GENMASK(11, 0)
#define YT921X_FDB_RESULT_INDEX(x) FIELD_PREP(YT921X_FDB_RESULT_INDEX_M, (x))
#define YT921X_FDB_OUT0 0x1804b0
#define YT921X_FDB_IO0_ADDR_HI4_M GENMASK(31, 0)
#define YT921X_FDB_OUT1 0x1804b4
#define YT921X_FDB_IO1_EGR_INT_PRI_EN BIT(31)
#define YT921X_FDB_IO1_STATUS_M GENMASK(30, 28)
#define YT921X_FDB_IO1_STATUS(x) FIELD_PREP(YT921X_FDB_IO1_STATUS_M, (x))
#define YT921X_FDB_IO1_STATUS_INVALID YT921X_FDB_IO1_STATUS(0)
#define YT921X_FDB_IO1_STATUS_MIN_TIME YT921X_FDB_IO1_STATUS(1)
#define YT921X_FDB_IO1_STATUS_MOVE_AGING_MAX_TIME YT921X_FDB_IO1_STATUS(3)
#define YT921X_FDB_IO1_STATUS_MAX_TIME YT921X_FDB_IO1_STATUS(5)
#define YT921X_FDB_IO1_STATUS_PENDING YT921X_FDB_IO1_STATUS(6)
#define YT921X_FDB_IO1_STATUS_STATIC YT921X_FDB_IO1_STATUS(7)
#define YT921X_FDB_IO1_FID_M GENMASK(27, 16) /* filtering ID (VID) */
#define YT921X_FDB_IO1_FID(x) FIELD_PREP(YT921X_FDB_IO1_FID_M, (x))
#define YT921X_FDB_IO1_ADDR_LO2_M GENMASK(15, 0)
#define YT921X_FDB_OUT2 0x1804b8
#define YT921X_FDB_IO2_MOVE_AGING_STATUS_M GENMASK(31, 30)
#define YT921X_FDB_IO2_IGR_DROP BIT(29)
#define YT921X_FDB_IO2_EGR_PORTS_M GENMASK(28, 18)
#define YT921X_FDB_IO2_EGR_PORTS(x) FIELD_PREP(YT921X_FDB_IO2_EGR_PORTS_M, (x))
#define YT921X_FDB_IO2_EGR_DROP BIT(17)
#define YT921X_FDB_IO2_COPY_TO_CPU BIT(16)
#define YT921X_FDB_IO2_IGR_INT_PRI_EN BIT(15)
#define YT921X_FDB_IO2_INT_PRI_M GENMASK(14, 12)
#define YT921X_FDB_IO2_INT_PRI(x) FIELD_PREP(YT921X_FDB_IO2_INT_PRI_M, (x))
#define YT921X_FDB_IO2_NEW_VID_M GENMASK(11, 0)
#define YT921X_FDB_IO2_NEW_VID(x) FIELD_PREP(YT921X_FDB_IO2_NEW_VID_M, (x))
#define YT921X_FILTER_UNK_UCAST 0x180508
#define YT921X_FILTER_UNK_MCAST 0x18050c
#define YT921X_FILTER_MCAST 0x180510
#define YT921X_FILTER_BCAST 0x180514
#define YT921X_FILTER_PORTS_M GENMASK(10, 0)
#define YT921X_FILTER_PORTS(x) FIELD_PREP(YT921X_FILTER_PORTS_M, (x))
#define YT921X_FILTER_PORTn(port) BIT(port)
#define YT921X_VLAN_EGR_FILTER 0x180598
#define YT921X_VLAN_EGR_FILTER_PORTn(port) BIT(port)
#define YT921X_CPU_COPY 0x180690
#define YT921X_CPU_COPY_FORCE_INT_PORT BIT(2)
#define YT921X_CPU_COPY_TO_INT_CPU BIT(1)
#define YT921X_CPU_COPY_TO_EXT_CPU BIT(0)
#define YT921X_ACT_UNK_UCAST 0x180734
#define YT921X_ACT_UNK_MCAST 0x180738
#define YT921X_ACT_UNK_MCAST_BYPASS_DROP_RMA BIT(23)
#define YT921X_ACT_UNK_MCAST_BYPASS_DROP_IGMP BIT(22)
#define YT921X_ACT_UNK_ACTn_M(port) GENMASK(2 * (port) + 1, 2 * (port))
#define YT921X_ACT_UNK_ACTn(port, x) ((x) << (2 * (port)))
#define YT921X_ACT_UNK_ACTn_FORWARD(port) YT921X_ACT_UNK_ACTn(port, 0) /* flood */
#define YT921X_ACT_UNK_ACTn_TRAP(port) YT921X_ACT_UNK_ACTn(port, 1) /* steer to CPU */
#define YT921X_ACT_UNK_ACTn_DROP(port) YT921X_ACT_UNK_ACTn(port, 2) /* discard */
/* NEVER use this action; see comments in the tag driver */
#define YT921X_ACT_UNK_ACTn_COPY(port) YT921X_ACT_UNK_ACTn(port, 3) /* flood and copy */
#define YT921X_FDB_HW_FLUSH 0x180958
#define YT921X_FDB_HW_FLUSH_ON_LINKDOWN BIT(0)
#define YT921X_VLANn_CTRL(vlan) (0x188000 + 8 * (vlan))
#define YT921X_VLAN_CTRL_UNTAG_PORTS_M GENMASK(50, 40)
#define YT921X_VLAN_CTRL_UNTAG_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_UNTAG_PORTS_M, (x))
#define YT921X_VLAN_CTRL_UNTAG_PORTn(port) BIT((port) + 40)
#define YT921X_VLAN_CTRL_STP_ID_M GENMASK(39, 36)
#define YT921X_VLAN_CTRL_STP_ID(x) FIELD_PREP(YT921X_VLAN_CTRL_STP_ID_M, (x))
#define YT921X_VLAN_CTRL_SVLAN_EN BIT(35)
#define YT921X_VLAN_CTRL_FID_M GENMASK(34, 23)
#define YT921X_VLAN_CTRL_FID(x) FIELD_PREP(YT921X_VLAN_CTRL_FID_M, (x))
#define YT921X_VLAN_CTRL_LEARN_DIS BIT(22)
#define YT921X_VLAN_CTRL_INT_PRI_EN BIT(21)
#define YT921X_VLAN_CTRL_INT_PRI_M GENMASK(20, 18)
#define YT921X_VLAN_CTRL_PORTS_M GENMASK(17, 7)
#define YT921X_VLAN_CTRL_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_PORTS_M, (x))
#define YT921X_VLAN_CTRL_PORTn(port) BIT((port) + 7)
#define YT921X_VLAN_CTRL_BYPASS_1X_AC BIT(6)
#define YT921X_VLAN_CTRL_METER_EN BIT(5)
#define YT921X_VLAN_CTRL_METER_ID_M GENMASK(4, 0)
#define YT921X_TPID_IGRn(x) (0x210000 + 4 * (x)) /* [0, 3] */
#define YT921X_TPID_IGR_TPID_M GENMASK(15, 0)
#define YT921X_PORTn_IGR_TPID(port) (0x210010 + 4 * (port))
#define YT921X_PORT_IGR_TPIDn_STAG_M GENMASK(7, 4)
#define YT921X_PORT_IGR_TPIDn_STAG(x) BIT((x) + 4)
#define YT921X_PORT_IGR_TPIDn_CTAG_M GENMASK(3, 0)
#define YT921X_PORT_IGR_TPIDn_CTAG(x) BIT(x)
#define YT921X_PORTn_VLAN_CTRL(port) (0x230010 + 4 * (port))
#define YT921X_PORT_VLAN_CTRL_SVLAN_PRI_EN BIT(31)
#define YT921X_PORT_VLAN_CTRL_CVLAN_PRI_EN BIT(30)
#define YT921X_PORT_VLAN_CTRL_SVID_M GENMASK(29, 18)
#define YT921X_PORT_VLAN_CTRL_SVID(x) FIELD_PREP(YT921X_PORT_VLAN_CTRL_SVID_M, (x))
#define YT921X_PORT_VLAN_CTRL_CVID_M GENMASK(17, 6)
#define YT921X_PORT_VLAN_CTRL_CVID(x) FIELD_PREP(YT921X_PORT_VLAN_CTRL_CVID_M, (x))
#define YT921X_PORT_VLAN_CTRL_SVLAN_PRI_M GENMASK(5, 3)
#define YT921X_PORT_VLAN_CTRL_CVLAN_PRI_M GENMASK(2, 0)
#define YT921X_PORTn_VLAN_CTRL1(port) (0x230080 + 4 * (port))
#define YT921X_PORT_VLAN_CTRL1_VLAN_RANGE_EN BIT(8)
#define YT921X_PORT_VLAN_CTRL1_VLAN_RANGE_PROFILE_ID_M GENMASK(7, 4)
#define YT921X_PORT_VLAN_CTRL1_SVLAN_DROP_TAGGED BIT(3)
#define YT921X_PORT_VLAN_CTRL1_SVLAN_DROP_UNTAGGED BIT(2)
#define YT921X_PORT_VLAN_CTRL1_CVLAN_DROP_TAGGED BIT(1)
#define YT921X_PORT_VLAN_CTRL1_CVLAN_DROP_UNTAGGED BIT(0)
#define YT921X_MIRROR 0x300300
#define YT921X_MIRROR_IGR_PORTS_M GENMASK(26, 16)
#define YT921X_MIRROR_IGR_PORTS(x) FIELD_PREP(YT921X_MIRROR_IGR_PORTS_M, (x))
#define YT921X_MIRROR_IGR_PORTn(port) BIT((port) + 16)
#define YT921X_MIRROR_EGR_PORTS_M GENMASK(14, 4)
#define YT921X_MIRROR_EGR_PORTS(x) FIELD_PREP(YT921X_MIRROR_EGR_PORTS_M, (x))
#define YT921X_MIRROR_EGR_PORTn(port) BIT((port) + 4)
#define YT921X_MIRROR_PORT_M GENMASK(3, 0)
#define YT921X_MIRROR_PORT(x) FIELD_PREP(YT921X_MIRROR_PORT_M, (x))
#define YT921X_EDATA_EXTMODE 0xfb
#define YT921X_EDATA_LEN 0x100
#define YT921X_FDB_NUM 4096
enum yt921x_fdb_entry_status {
YT921X_FDB_ENTRY_STATUS_INVALID = 0,
YT921X_FDB_ENTRY_STATUS_MIN_TIME = 1,
YT921X_FDB_ENTRY_STATUS_MOVE_AGING_MAX_TIME = 3,
YT921X_FDB_ENTRY_STATUS_MAX_TIME = 5,
YT921X_FDB_ENTRY_STATUS_PENDING = 6,
YT921X_FDB_ENTRY_STATUS_STATIC = 7,
};
#define YT9215_MAJOR 0x9002
#define YT9218_MAJOR 0x9001
/* required for a hard reset */
#define YT921X_RST_DELAY_US 10000
#define YT921X_FRAME_SIZE_MAX 0x2400 /* 9216 */
#define YT921X_TAG_LEN 8
/* 8 internal + 2 external + 1 mcu */
#define YT921X_PORT_NUM 11
#define yt921x_port_is_internal(port) ((port) < 8)
#define yt921x_port_is_external(port) (8 <= (port) && (port) < 9)
struct yt921x_mib {
u64 rx_broadcast;
u64 rx_pause;
u64 rx_multicast;
u64 rx_crc_errors;
u64 rx_alignment_errors;
u64 rx_undersize_errors;
u64 rx_fragment_errors;
u64 rx_64byte;
u64 rx_65_127byte;
u64 rx_128_255byte;
u64 rx_256_511byte;
u64 rx_512_1023byte;
u64 rx_1024_1518byte;
u64 rx_jumbo;
u64 rx_good_bytes;
u64 rx_bad_bytes;
u64 rx_oversize_errors;
u64 rx_dropped;
u64 tx_broadcast;
u64 tx_pause;
u64 tx_multicast;
u64 tx_undersize_errors;
u64 tx_64byte;
u64 tx_65_127byte;
u64 tx_128_255byte;
u64 tx_256_511byte;
u64 tx_512_1023byte;
u64 tx_1024_1518byte;
u64 tx_jumbo;
u64 tx_good_bytes;
u64 tx_collisions;
u64 tx_aborted_errors;
u64 tx_multiple_collisions;
u64 tx_single_collisions;
u64 tx_good;
u64 tx_deferred;
u64 tx_late_collisions;
u64 rx_oam;
u64 tx_oam;
};
struct yt921x_port {
unsigned char index;
bool hairpin;
bool isolated;
struct delayed_work mib_read;
struct yt921x_mib mib;
u64 rx_frames;
u64 tx_frames;
};
struct yt921x_reg_ops {
int (*read)(void *context, u32 reg, u32 *valp);
int (*write)(void *context, u32 reg, u32 val);
};
struct yt921x_priv {
struct dsa_switch ds;
const struct yt921x_info *info;
/* cache of dsa_cpu_ports(ds) */
u16 cpu_ports_mask;
/* protect the access to the switch registers */
struct mutex reg_lock;
const struct yt921x_reg_ops *reg_ops;
void *reg_ctx;
/* mdio master bus */
struct mii_bus *mbus_int;
struct mii_bus *mbus_ext;
struct yt921x_port ports[YT921X_PORT_NUM];
u16 eee_ports_mask;
};
#endif

View File

@@ -55,6 +55,7 @@ struct tc_action;
#define DSA_TAG_PROTO_LAN937X_VALUE 27
#define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28
#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29
#define DSA_TAG_PROTO_YT921X_VALUE 30
enum dsa_tag_protocol {
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -87,6 +88,7 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_RZN1_A5PSW = DSA_TAG_PROTO_RZN1_A5PSW_VALUE,
DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE,
DSA_TAG_PROTO_VSC73XX_8021Q = DSA_TAG_PROTO_VSC73XX_8021Q_VALUE,
DSA_TAG_PROTO_YT921X = DSA_TAG_PROTO_YT921X_VALUE,
};
struct dsa_switch;

View File

@@ -114,6 +114,7 @@
#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_YT921X 0x9988 /* Motorcomm YT921x DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_DSA_8021Q 0xDADB /* Fake VLAN Header for DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_DSA_A5PSW 0xE001 /* A5PSW Tag Value [ NOT AN OFFICIALLY REGISTERED ID ] */

View File

@@ -190,4 +190,10 @@ config NET_DSA_TAG_XRS700X
Say Y or M if you want to enable support for tagging frames for
Arrow SpeedChips XRS700x switches that use a single byte tag trailer.
config NET_DSA_TAG_YT921X
tristate "Tag driver for Motorcomm YT921x switches"
help
Say Y or M if you want to enable support for tagging frames for
Motorcomm YT921x switches.
endif

View File

@@ -39,6 +39,7 @@ obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
obj-$(CONFIG_NET_DSA_TAG_VSC73XX_8021Q) += tag_vsc73xx_8021q.o
obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o
obj-$(CONFIG_NET_DSA_TAG_YT921X) += tag_yt921x.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)

141
net/dsa/tag_yt921x.c Normal file
View File

@@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Motorcomm YT921x Switch Extended CPU Port Tagging
*
* Copyright (c) 2025 David Yang <mmyangfl@gmail.com>
*
* +----+----+-------+-----+----+---------
* | DA | SA | TagET | Tag | ET | Payload ...
* +----+----+-------+-----+----+---------
* 6 6 2 6 2 N
*
* Tag Ethertype: CPU_TAG_TPID_TPID (default: ETH_P_YT921X = 0x9988)
* * Hardcoded for the moment, but still configurable. Discuss it if there
* are conflicts somewhere and/or you want to change it for some reason.
* Tag:
* 2: VLAN Tag
* 2: Rx Port
* 15b: Rx Port Valid
* 14b-11b: Rx Port
* 10b-0b: Cmd?
* 2: Tx Port(s)
* 15b: Tx Port(s) Valid
* 10b-0b: Tx Port(s) Mask
*/
#include <linux/etherdevice.h>
#include "tag.h"
#define YT921X_TAG_NAME "yt921x"
#define YT921X_TAG_LEN 8
#define YT921X_TAG_PORT_EN BIT(15)
#define YT921X_TAG_RX_PORT_M GENMASK(14, 11)
#define YT921X_TAG_RX_CMD_M GENMASK(10, 0)
#define YT921X_TAG_RX_CMD(x) FIELD_PREP(YT921X_TAG_RX_CMD_M, (x))
#define YT921X_TAG_RX_CMD_FORWARDED 0x80
#define YT921X_TAG_RX_CMD_UNK_UCAST 0xb2
#define YT921X_TAG_RX_CMD_UNK_MCAST 0xb4
#define YT921X_TAG_TX_PORTS_M GENMASK(10, 0)
#define YT921X_TAG_TX_PORTn(port) BIT(port)
static struct sk_buff *
yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct dsa_port *dp = dsa_user_to_port(netdev);
unsigned int port = dp->index;
__be16 *tag;
u16 tx;
skb_push(skb, YT921X_TAG_LEN);
dsa_alloc_etype_header(skb, YT921X_TAG_LEN);
tag = dsa_etype_header_pos_tx(skb);
tag[0] = htons(ETH_P_YT921X);
/* VLAN tag unrelated when TX */
tag[1] = 0;
tag[2] = 0;
tx = YT921X_TAG_PORT_EN | YT921X_TAG_TX_PORTn(port);
tag[3] = htons(tx);
return skb;
}
static struct sk_buff *
yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
{
unsigned int port;
__be16 *tag;
u16 cmd;
u16 rx;
if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN)))
return NULL;
tag = dsa_etype_header_pos_rx(skb);
if (unlikely(tag[0] != htons(ETH_P_YT921X))) {
dev_warn_ratelimited(&netdev->dev,
"Unexpected EtherType 0x%04x\n",
ntohs(tag[0]));
return NULL;
}
/* Locate which port this is coming from */
rx = ntohs(tag[2]);
if (unlikely((rx & YT921X_TAG_PORT_EN) == 0)) {
dev_warn_ratelimited(&netdev->dev,
"Unexpected rx tag 0x%04x\n", rx);
return NULL;
}
port = FIELD_GET(YT921X_TAG_RX_PORT_M, rx);
skb->dev = dsa_conduit_find_user(netdev, 0, port);
if (unlikely(!skb->dev)) {
dev_warn_ratelimited(&netdev->dev,
"Couldn't decode source port %u\n", port);
return NULL;
}
cmd = FIELD_GET(YT921X_TAG_RX_CMD_M, rx);
switch (cmd) {
case YT921X_TAG_RX_CMD_FORWARDED:
/* Already forwarded by hardware */
dsa_default_offload_fwd_mark(skb);
break;
case YT921X_TAG_RX_CMD_UNK_UCAST:
case YT921X_TAG_RX_CMD_UNK_MCAST:
/* NOTE: hardware doesn't distinguish between TRAP (copy to CPU
* only) and COPY (forward and copy to CPU). In order to perform
* a soft switch, NEVER use COPY action in the switch driver.
*/
break;
default:
dev_warn_ratelimited(&netdev->dev,
"Unexpected rx cmd 0x%02x\n", cmd);
break;
}
/* Remove YT921x tag and update checksum */
skb_pull_rcsum(skb, YT921X_TAG_LEN);
dsa_strip_etype_header(skb, YT921X_TAG_LEN);
return skb;
}
static const struct dsa_device_ops yt921x_netdev_ops = {
.name = YT921X_TAG_NAME,
.proto = DSA_TAG_PROTO_YT921X,
.xmit = yt921x_tag_xmit,
.rcv = yt921x_tag_rcv,
.needed_headroom = YT921X_TAG_LEN,
};
MODULE_DESCRIPTION("DSA tag driver for Motorcomm YT921x switches");
MODULE_LICENSE("GPL");
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_YT921X, YT921X_TAG_NAME);
module_dsa_tag_driver(yt921x_netdev_ops);