Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen
2026-06-02 14:54:29 +08:00
279 changed files with 28357 additions and 4685 deletions
+5 -1
View File
@@ -898,9 +898,13 @@ define Device/Build
$$(call Device/Build/compile,$$(compile),$(1))))
$$(eval $$(foreach image,$$(IMAGES), \
$$(foreach fs,$$(filter $(TARGET_FILESYSTEMS),$$(FILESYSTEMS)), \
$$(foreach fs,$$(filter $$(filter-out targz,$(TARGET_FILESYSTEMS)),$$(FILESYSTEMS)), \
$$(call Device/Build/image,$$(fs),$$(image),$(1)))))
$(if $(CONFIG_TARGET_ROOTFS_TARGZ), \
IMAGE/rootfs.tar.gz := append-rootfs
$$(eval $$(call Device/Build/image,targz,rootfs.tar.gz,$(1))))
$$(eval $$(foreach artifact,$$(ARTIFACTS), \
$$(call Device/Build/artifact,$$(artifact),$(1))))
@@ -0,0 +1,42 @@
#
# Copyright (C) 2026 Martin Schiller <ms@dev.tdt.de>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_VERSION:=2.14.0
PKG_RELEASE:=1
PKG_HASH:=b2a3bc360307c929714ffd8e7f1441c4888cd5d80531276e809c2de54db5dc16
PKG_MAINTAINER:=Martin Schiller <ms@dev.tdt.de>
include $(INCLUDE_DIR)/kernel.mk
include $(INCLUDE_DIR)/trusted-firmware-a.mk
include $(INCLUDE_DIR)/package.mk
define Trusted-Firmware-A/Default
BUILD_TARGET:=imx
BUILD_SUBTARGET:=cortexa53
endef
define Trusted-Firmware-A/imx8mp
NAME:=NXP i.MX8MP
PLAT:=imx8mp
endef
TFA_TARGETS:= \
imx8mp
TFA_MAKE_FLAGS += \
IMX_BOOT_UART_BASE="auto"
define Package/trusted-firmware-a/install
$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
$(INSTALL_DATA) $(PKG_BUILD_DIR)/build/$(PLAT)/release/bl31.bin $(STAGING_DIR_IMAGE)/bl31_$(BUILD_VARIANT).bin
endef
$(eval $(call BuildPackage/Trusted-Firmware-A))
+22 -3
View File
@@ -7,10 +7,10 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=2022.01
PKG_RELEASE:=5
PKG_VERSION:=2026.04
PKG_RELEASE:=1
PKG_HASH:=81b4543227db228c03f8a1bf5ddbc813b0bb8f6555ce46064ef721a6fc680413
PKG_HASH:=ac7c04b8b7004923b00a4e5d6699c5df4d21233bac9fda690d8cfbc209fff2fd
include $(INCLUDE_DIR)/u-boot.mk
include $(INCLUDE_DIR)/package.mk
@@ -28,6 +28,15 @@ define U-Boot/apalis_imx6
BUILD_DEVICES:=toradex_apalis
endef
define U-Boot/kontron-osm-s-mx8mp
NAME:=Kontron OSM-S/BL i.MX8MP
DEPENDS:=+firmware-imx +trusted-firmware-a-imx8mp
ATF:=bl31_imx8mp.bin
UBOOT_IMAGE:=flash.bin
BUILD_SUBTARGET:=cortexa53
BUILD_DEVICES:=kontron_osm-s-imx8mp
endef
define U-Boot/mx6cuboxi
NAME:=SolidRun Cubox-i boards
UBOOT_IMAGE:=SPL u-boot-dtb.img
@@ -52,11 +61,18 @@ endef
UBOOT_TARGETS := \
apalis_imx6 \
kontron-osm-s-mx8mp \
mx6cuboxi \
pico-pi-imx7d \
wandboard
ifneq ($(SUBTARGET),cortexa53)
UBOOT_MAKE_FLAGS += u-boot.imx
else
UBOOT_MAKE_FLAGS += \
BL31=$(STAGING_DIR_IMAGE)/$(ATF) \
BINMAN_INDIRS="$(STAGING_DIR_IMAGE)/firmware-imx $(STAGING_DIR_IMAGE)"
endif
define Build/InstallDev
$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
@@ -65,4 +81,7 @@ define Build/InstallDev
)
endef
define Package/u-boot/install/default
endef
$(eval $(call BuildPackage/U-Boot))
@@ -16,7 +16,7 @@ Signed-off-by: Petr Štetiar <ynezz@true.cz>
--- a/configs/apalis_imx6_defconfig
+++ b/configs/apalis_imx6_defconfig
@@ -60,6 +60,7 @@ CONFIG_CMD_CACHE=y
@@ -66,6 +66,7 @@ CONFIG_CMD_CACHE=y
CONFIG_CMD_TIME=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
@@ -13,7 +13,7 @@ Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
create mode 100644 configs/mangopi_mqdual_t113_defconfig
--- /dev/null
+++ b/arch/arm/dts/sun8i-t113s-mangopi-mqdual-t113.dts
+++ b/dts/upstream/src/arm/allwinner/sun8i-t113s-mangopi-mqdual-t113.dts
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// Copyright (C) 2022 Arm Ltd.
@@ -67,10 +67,10 @@ Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+};
--- /dev/null
+++ b/configs/mangopi_mqdual_t113_defconfig
@@ -0,0 +1,18 @@
@@ -0,0 +1,17 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-mangopi-mqdual-t113"
+CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun8i-t113s-mangopi-mqdual-t113"
+CONFIG_SUNXI_MINIMUM_DRAM_MB=128
+CONFIG_SPL=y
+CONFIG_MACH_SUN8I_R528=y
@@ -85,4 +85,3 @@ Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+CONFIG_DRAM_SUNXI_TPR11=0x340000
+CONFIG_DRAM_SUNXI_TPR12=0x46
+CONFIG_DRAM_SUNXI_TPR13=0x34000100
+# CONFIG_OF_UPSTREAM is not set
@@ -1,5 +1,79 @@
--- /dev/null
+++ b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-emmc.dts
+++ b/configs/myir_myd_t113x-emmc_defconfig
@@ -0,0 +1,29 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun8i-t113s-myir-myd-yt113x-emmc"
+CONFIG_SUNXI_MINIMUM_DRAM_MB=128
+CONFIG_SPL=y
+CONFIG_MACH_SUN8I_R528=y
+CONFIG_CONS_INDEX=6
+CONFIG_MMC0_CD_PIN="PF6"
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SYS_MONITOR_LEN=786432
+CONFIG_DRAM_CLK=792
+CONFIG_DRAM_ZQ=8092667
+CONFIG_DRAM_SUNXI_ODT_EN=0
+CONFIG_DRAM_SUNXI_TPR0=0x004a2195
+CONFIG_DRAM_SUNXI_TPR11=0x340000
+CONFIG_DRAM_SUNXI_TPR12=0x46
+CONFIG_DRAM_SUNXI_TPR13=0x34000100
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_PHY_MOTORCOMM=y
+CONFIG_SUN8I_EMAC=y
+CONFIG_RGMII=y
+CONFIG_RMII=y
+CONFIG_SUPPORT_EMMC_BOOT=y
+CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_SPL_MMC_IO_VOLTAGE=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_SPL_MMC_HS200_SUPPORT=y
--- /dev/null
+++ b/configs/myir_myd_t113x-spi_defconfig
@@ -0,0 +1,39 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun8i-t113s-myir-myd-yt113x-spi"
+CONFIG_SUNXI_MINIMUM_DRAM_MB=128
+CONFIG_SPL=y
+CONFIG_SPL_SPI_SUNXI=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MACH_SUN8I_R528=y
+CONFIG_CONS_INDEX=6
+CONFIG_MMC0_CD_PIN="PF6"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SYS_MONITOR_LEN=786432
+CONFIG_DRAM_CLK=792
+CONFIG_DRAM_ZQ=8092667
+CONFIG_DRAM_SUNXI_ODT_EN=0
+CONFIG_DRAM_SUNXI_TPR0=0x004a2195
+CONFIG_DRAM_SUNXI_TPR11=0x340000
+CONFIG_DRAM_SUNXI_TPR12=0x46
+CONFIG_DRAM_SUNXI_TPR13=0x34000100
+CONFIG_CLK_SUN20I_D1=y
+CONFIG_PHY_MOTORCOMM=y
+CONFIG_SUN8I_EMAC=y
+CONFIG_RGMII=y
+CONFIG_RMII=y
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_SYS_MTDPARTS_RUNTIME=y
+CONFIG_NAND_STM32_FMC2=y
+CONFIG_SYS_NAND_ONFI_DETECTION=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_SPI=y
+CONFIG_MTD_UBI_FASTMAP=y
--- /dev/null
+++ b/dts/upstream/src/arm/allwinner/sun8i-t113s-myir-myd-yt113x-emmc.dts
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// Copyright (C) 2022 Arm Ltd.
@@ -34,7 +108,7 @@
+ };
+};
--- /dev/null
+++ b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
+++ b/dts/upstream/src/arm/allwinner/sun8i-t113s-myir-myd-yt113x-spi.dts
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// Copyright (C) 2025 Zoltan HERPAI <wigyori@uid0.hu>
@@ -87,83 +161,7 @@
+ };
+};
--- /dev/null
+++ b/configs/myir_myd_t113x-emmc_defconfig
@@ -0,0 +1,30 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-myir-myd-yt113x-emmc"
+CONFIG_SUNXI_MINIMUM_DRAM_MB=128
+CONFIG_SPL=y
+CONFIG_MACH_SUN8I_R528=y
+CONFIG_CONS_INDEX=6
+CONFIG_MMC0_CD_PIN="PF6"
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SYS_MONITOR_LEN=786432
+CONFIG_DRAM_CLK=792
+CONFIG_DRAM_ZQ=8092667
+CONFIG_DRAM_SUNXI_ODT_EN=0
+CONFIG_DRAM_SUNXI_TPR0=0x004a2195
+CONFIG_DRAM_SUNXI_TPR11=0x340000
+CONFIG_DRAM_SUNXI_TPR12=0x46
+CONFIG_DRAM_SUNXI_TPR13=0x34000100
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_PHY_MOTORCOMM=y
+CONFIG_SUN8I_EMAC=y
+CONFIG_RGMII=y
+CONFIG_RMII=y
+CONFIG_SUPPORT_EMMC_BOOT=y
+CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_SPL_MMC_IO_VOLTAGE=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_SPL_MMC_HS200_SUPPORT=y
+# CONFIG_OF_UPSTREAM is not set
--- /dev/null
+++ b/configs/myir_myd_t113x-spi_defconfig
@@ -0,0 +1,40 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-myir-myd-yt113x-spi"
+CONFIG_SUNXI_MINIMUM_DRAM_MB=128
+CONFIG_SPL=y
+CONFIG_SPL_SPI_SUNXI=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MACH_SUN8I_R528=y
+CONFIG_CONS_INDEX=6
+CONFIG_MMC0_CD_PIN="PF6"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SYS_MONITOR_LEN=786432
+CONFIG_DRAM_CLK=792
+CONFIG_DRAM_ZQ=8092667
+CONFIG_DRAM_SUNXI_ODT_EN=0
+CONFIG_DRAM_SUNXI_TPR0=0x004a2195
+CONFIG_DRAM_SUNXI_TPR11=0x340000
+CONFIG_DRAM_SUNXI_TPR12=0x46
+CONFIG_DRAM_SUNXI_TPR13=0x34000100
+CONFIG_CLK_SUN20I_D1=y
+CONFIG_PHY_MOTORCOMM=y
+CONFIG_SUN8I_EMAC=y
+CONFIG_RGMII=y
+CONFIG_RMII=y
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_SYS_MTDPARTS_RUNTIME=y
+CONFIG_NAND_STM32_FMC2=y
+CONFIG_SYS_NAND_ONFI_DETECTION=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_SPI=y
+CONFIG_MTD_UBI_FASTMAP=y
+# CONFIG_OF_UPSTREAM is not set
--- /dev/null
+++ b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x.dtsi
+++ b/dts/upstream/src/arm/allwinner/sun8i-t113s-myir-myd-yt113x.dtsi
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// Copyright (C) 2025 Zoltan HERPAI <wigyori@uid0.hu>
@@ -13,7 +13,7 @@ Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
create mode 100644 configs/rongpin_rp_t113_defconfig
--- /dev/null
+++ b/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
+++ b/dts/upstream/src/arm/allwinner/sun8i-t113s-rongpin-rp-t113.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// Copyright (C) 2022 Arm Ltd.
@@ -116,10 +116,10 @@ Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+};
--- /dev/null
+++ b/configs/rongpin_rp_t113_defconfig
@@ -0,0 +1,19 @@
@@ -0,0 +1,18 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-rongpin-rp-t113"
+CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun8i-t113s-rongpin-rp-t113"
+CONFIG_SUNXI_MINIMUM_DRAM_MB=128
+CONFIG_SPL=y
+CONFIG_MACH_SUN8I_R528=y
@@ -135,4 +135,3 @@ Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+CONFIG_DRAM_SUNXI_TPR12=0x46
+CONFIG_DRAM_SUNXI_TPR13=0x34000100
+CONFIG_UART3_PINS_PE=y
+# CONFIG_OF_UPSTREAM is not set
@@ -27,8 +27,8 @@ Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
configs/rongpin_rp_t113_defconfig | 3 +++
2 files changed, 31 insertions(+)
--- a/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
+++ b/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
--- a/dts/upstream/src/arm/allwinner/sun8i-t113s-rongpin-rp-t113.dts
+++ b/dts/upstream/src/arm/allwinner/sun8i-t113s-rongpin-rp-t113.dts
@@ -55,6 +55,16 @@
regulator-max-microvolt = <2800000>;
vin-supply = <&reg_3v3>;
@@ -77,10 +77,10 @@ Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+};
--- a/configs/rongpin_rp_t113_defconfig
+++ b/configs/rongpin_rp_t113_defconfig
@@ -17,3 +17,6 @@ CONFIG_DRAM_SUNXI_TPR12=0x46
@@ -16,3 +16,6 @@ CONFIG_DRAM_SUNXI_TPR11=0x340000
CONFIG_DRAM_SUNXI_TPR12=0x46
CONFIG_DRAM_SUNXI_TPR13=0x34000100
CONFIG_UART3_PINS_PE=y
# CONFIG_OF_UPSTREAM is not set
+CONFIG_SUN8I_EMAC=y
+CONFIG_PHY_ICPLUS=y
+CONFIG_RMII=y
@@ -1,5 +1,5 @@
--- /dev/null
+++ b/arch/arm/dts/sun8i-t113s-olinuxino.dts
+++ b/dts/upstream/src/arm/allwinner/sun8i-t113s-olinuxino.dts
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// Copyright (C) 2022 Arm Ltd.
@@ -196,10 +196,10 @@
+};
--- /dev/null
+++ b/configs/olimex_olinuxino_defconfig
@@ -0,0 +1,42 @@
@@ -0,0 +1,41 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-olinuxino"
+CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun8i-t113s-olinuxino"
+CONFIG_SUNXI_MINIMUM_DRAM_MB=128
+CONFIG_SPL=y
+CONFIG_MACH_SUN8I_R528=y
@@ -238,4 +238,3 @@
+CONFIG_SPL_SPI_FLASH_MTD=y
+CONFIG_SPL_SPI_SUNXI=y
+CONFIG_SPI=y
+# CONFIG_OF_UPSTREAM is not set
+44
View File
@@ -0,0 +1,44 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright 2022-2025 NXP
#
include $(TOPDIR)/rules.mk
PKG_NAME:=firmware-imx
PKG_VERSION:=8.28-994fa14
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).bin
PKG_SOURCE_URL:=https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/
PKG_HASH:=55996f340e87825685a00cd309901189066ec9545ee607734f942c3cde4d69dc
PKG_LICENSE:=LA_OPT_NXP_Software_License
PKG_LICENSE_FILES:=COPYING
include $(INCLUDE_DIR)/package.mk
define Package/firmware-imx
SECTION:=firmware
CATEGORY:=Firmware
TITLE:=NXP firmware for i.MX SoC
DEPENDS:=@TARGET_imx_cortexa53
endef
UNPACK_CMD:=
define Build/Compile
$(PKG_UNPACK)
$(CP) $(DL_DIR)/$(PKG_SOURCE) $(PKG_BUILD_DIR)
chmod a+x $(PKG_BUILD_DIR)/$(PKG_SOURCE)
cd $(PKG_BUILD_DIR) && ./$(PKG_SOURCE) --auto-accept
endef
define Build/InstallDev
$(INSTALL_DIR) $(STAGING_DIR_IMAGE)/firmware-imx
$(CP) $(PKG_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)/firmware/ddr/synopsys/* \
$(STAGING_DIR_IMAGE)/firmware-imx/
$(CP) $(PKG_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)/firmware/hdmi/cadence/* \
$(STAGING_DIR_IMAGE)/firmware-imx/
endef
$(eval $(call BuildPackage,firmware-imx))
+3 -2
View File
@@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=linux-firmware
PKG_VERSION:=20260410
PKG_VERSION:=20260519
PKG_RELEASE:=1
PKG_SOURCE_URL:=@KERNEL/linux/kernel/firmware
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_HASH:=b7812ed6d59f6b09ecceddaa0be842a7e82a79cc0e46ca60478a4ebf02f1e178
PKG_HASH:=b14e7197a290a7e5569f5ef790cde289bddc47e32126f2eb262a8e677fc39727
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
@@ -32,6 +32,7 @@ define Package/firmware-default
DEPENDS:=$(2)
LICENSE_FILES:=$(3)
LICENSE:=$(4)
$(if $(5),PKGFLAGS:=$(5))
endef
define Build/Compile
+2 -2
View File
@@ -97,7 +97,7 @@ define Package/mt7986-wo-firmware/install
endef
$(eval $(call BuildPackage,mt7986-wo-firmware))
Package/mt7987-2p5g-phy-firmware = $(call Package/firmware-default,MT7987 built-in 2.5G Ethernet PHY firmware,+LINUX_6_18:kmod-phy-mediatek-2p5g,LICENCE.mediatek)
Package/mt7987-2p5g-phy-firmware = $(call Package/firmware-default,MT7987 built-in 2.5G Ethernet PHY firmware,@TARGET_mediatek_filogic +LINUX_6_18:kmod-phy-mediatek-2p5g,LICENCE.mediatek,,nonshared)
define Package/mt7987-2p5g-phy-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7987
$(INSTALL_DATA) \
@@ -107,7 +107,7 @@ define Package/mt7987-2p5g-phy-firmware/install
endef
$(eval $(call BuildPackage,mt7987-2p5g-phy-firmware))
Package/mt7988-2p5g-phy-firmware = $(call Package/firmware-default,MT7988 built-in 2.5G Ethernet PHY firmware,+LINUX_6_18:kmod-phy-mediatek-2p5g,LICENCE.mediatek)
Package/mt7988-2p5g-phy-firmware = $(call Package/firmware-default,MT7988 built-in 2.5G Ethernet PHY firmware,@TARGET_mediatek_filogic +LINUX_6_18:kmod-phy-mediatek-2p5g,LICENCE.mediatek,,nonshared)
define Package/mt7988-2p5g-phy-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7988
$(INSTALL_DATA) \
@@ -365,6 +365,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
{
struct device_node *node = dev->of_node;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *buttons;
int nbuttons;
int i = 0;
@@ -372,21 +373,12 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (nbuttons == 0)
return ERR_PTR(-EINVAL);
pdata = devm_kzalloc(dev, sizeof(struct gpio_keys_platform_data), GFP_KERNEL);
if (!pdata)
buttons = devm_kmalloc_array(dev, nbuttons, sizeof(struct gpio_keys_button), GFP_KERNEL);
if (!buttons)
return ERR_PTR(-ENOMEM);
pdata->buttons = devm_kmalloc_array(dev, nbuttons, sizeof(struct gpio_keys_button), GFP_KERNEL);
if (!pdata->buttons)
return ERR_PTR(-ENOMEM);
pdata->nbuttons = nbuttons;
pdata->rep = of_property_present(node, "autorepeat");
of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
for_each_available_child_of_node_scoped(node, pp) {
struct gpio_keys_button *button = (struct gpio_keys_button *)&pdata->buttons[i++];
struct gpio_keys_button *button = &buttons[i++];
if (of_property_read_u32(pp, "linux,code", &button->code)) {
dev_err(dev, "Button node '%s' without keycode\n",
@@ -409,6 +401,15 @@ gpio_keys_get_devtree_pdata(struct device *dev)
button->gpio = -ENOENT; /* mark this as device-tree */
}
pdata = devm_kzalloc(dev, sizeof(struct gpio_keys_platform_data), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->nbuttons = nbuttons;
pdata->buttons = buttons;
pdata->rep = of_property_present(node, "autorepeat");
of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
return pdata;
}
+2 -2
View File
@@ -1133,8 +1133,8 @@ define KernelPackage/crypto-sha512/arm
endef
define KernelPackage/crypto-sha512/aarch64
FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha512-arm64.ko
AUTOLOAD+=$(call AutoLoad,09,sha512-arm64)
FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha512-arm64.ko@lt6.18
AUTOLOAD+=$(call AutoLoad,09,!LINUX_6_18:sha512-arm64)
endef
KernelPackage/crypto-sha512/imx/cortexa7=$(KernelPackage/crypto-sha512/arm)
+17
View File
@@ -221,6 +221,23 @@ endef
$(eval $(call KernelPackage,rtc-rs5c372a))
define KernelPackage/rtc-rv3028
SUBMENU:=$(RTC_MENU)
TITLE:=Micro Crystal RV3028
DEFAULT:=m if ALL_KMODS && RTC_SUPPORT
DEPENDS:=+kmod-i2c-core +kmod-regmap-i2c
KCONFIG:=CONFIG_RTC_DRV_RV3028 \
CONFIG_RTC_CLASS=y
FILES:=$(LINUX_DIR)/drivers/rtc/rtc-rv3028.ko
AUTOLOAD:=$(call AutoLoad,50,rtc-rv3028,1)
endef
define KernelPackage/rtc-rv3028/description
Kernel module for Micro Crystal RV3028 I2C RTC chip
endef
$(eval $(call KernelPackage,rtc-rv3028))
define KernelPackage/rtc-rx8025
SUBMENU:=$(RTC_MENU)
TITLE:=Epson RX-8025 / RX-8035
@@ -0,0 +1,59 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 23 Mar 2026 10:14:22 +0000
Subject: [PATCH] wifi: mac80211: add ieee80211_txq_aql_pending()
Add a function to allow drivers to query the pending AQL airtime
for a given txq, for both unicast and broadcast.
This will be used for mt76 to limit buffering in AP mode for power-save
stations.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6603,6 +6603,17 @@ bool
ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
/**
+ * ieee80211_txq_aql_pending - get pending AQL airtime for a txq
+ *
+ * @hw: pointer obtained from ieee80211_alloc_hw()
+ * @txq: pointer obtained from station or virtual interface
+ *
+ * Return: pending airtime (in usec) for the given txq.
+ */
+u32 ieee80211_txq_aql_pending(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq);
+
+/**
* ieee80211_iter_keys - iterate keys programmed into the device
* @hw: pointer obtained from ieee80211_alloc_hw()
* @vif: virtual interface to iterate, may be %NULL for all
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4185,6 +4185,24 @@ bool ieee80211_txq_airtime_check(struct
}
EXPORT_SYMBOL(ieee80211_txq_airtime_check);
+u32 ieee80211_txq_aql_pending(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+
+ if (!txq->sta)
+ return atomic_read(&local->aql_bc_pending_airtime);
+
+ sta = container_of(txq->sta, struct sta_info, sta);
+
+ if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
+ return 0;
+
+ return atomic_read(&sta->airtime[txq->ac].aql_tx_pending);
+}
+EXPORT_SYMBOL(ieee80211_txq_aql_pending);
+
static bool
ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac)
{
+38 -1
View File
@@ -535,6 +535,28 @@ menu "Resource limits"
Possible values: 1 to 80 (from src/sysoptions.h)
Default: 10
config DROPBEAR_MAX_PUBKEY_QUERIES
int "Max. public key queries per session"
range 1 80
default 15
help
Default maximum number of public key queries per session (server option).
Public key queries aren't a risk for brute forcing authentication,
but can be a user enumeration/privacy concern if an attacker
attempts to iterate known public keys such as those published by GitHub.
This limit has a trade-off. Having a smaller limit reduces the number
of legitimate public keys that can be presented by a client/ssh agent.
That is still a risk against a single host,
but this limit may deter internet-wide scanning.
If -T argument or DROPBEAR_MAX_AUTH_TRIES is larger that will be used instead.
Possible values: 1 to 80 (same as for DROPBEAR_MAX_AUTH_TRIES)
Default: 15
config DROPBEAR_UNAUTH_CLOSE_DELAY
int "Delay closing unauth. connections (seconds)"
range 0 3600
@@ -640,6 +662,21 @@ menu "Resource limits"
Possible values: 0 to 604800 (7 days)
Default: 0 (disabled).
config DROPBEAR_DEFAULT_MAX_DURATION
int "Default max. session duration (seconds)"
range 0 604800
default 0
help
If session duration exceeds specified limit, disconnect.
Applies to both server and client.
Note: values below 30 seconds are not recommended.
This can be changed at run-time with the -M argument.
Possible values: 0 to 604800 (7 days)
Default: 0 (disabled).
endmenu
## </RESOURCE LIMITS>
@@ -985,7 +1022,7 @@ menu "Encryption options"
Post-quantum KEM can avoid harvest-now-decrypt-later style attacks.
Default: enabled, except devices with very small flash.
Default: disabled.
config DROPBEAR_SNTRUP761
bool "sntrup761 [POST-QUANTUM]"
+5 -3
View File
@@ -8,14 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dropbear
PKG_VERSION:=2025.89
PKG_VERSION:=2026.91
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:= \
https://matt.ucc.asn.au/dropbear/releases/ \
https://dropbear.nl/mirror/releases/
PKG_HASH:=0d1f7ca711cfc336dc8a85e672cab9cfd8223a02fe2da0a4a7aeb58c9e113634
PKG_HASH:=defa924475abf6bc1e74abc00173e46bfdc804bd47caafa14f5a4ef0cc76da34
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE libtomcrypt/LICENSE libtommath/LICENSE
@@ -32,7 +32,7 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_DROPBEAR_DO_HOST_LOOKUP CONFIG_DROPBEAR_SVR_PUBKEY_OPTIONS CONFIG_DROPBEAR_LASTLOG CONFIG_DROPBEAR_LASTLOG_PATH CONFIG_DROPBEAR_WTMP CONFIG_DROPBEAR_WTMP_PATH CONFIG_DROPBEAR_UTMP CONFIG_DROPBEAR_UTMP_PATH CONFIG_DROPBEAR_PUTUTLINE CONFIG_DROPBEAR_LOGINFUNC \
CONFIG_DROPBEAR_REEXEC CONFIG_DROPBEAR_ZLIB CONFIG_DROPBEAR_DELAY_HOSTKEY CONFIG_DROPBEAR_SVR_AGENTFWD CONFIG_DROPBEAR_SVR_REMOTETCPFWD CONFIG_DROPBEAR_SVR_LOCALTCPFWD CONFIG_DROPBEAR_SVR_LOCALSTREAMFWD CONFIG_DROPBEAR_X11FWD CONFIG_DROPBEAR_SCP CONFIG_DROPBEAR_SFTPSERVER \
CONFIG_DROPBEAR_DBCLIENT CONFIG_DROPBEAR_USER_ALGO_LIST CONFIG_DROPBEAR_USE_SSH_CONFIG CONFIG_DROPBEAR_CLI_IMMEDIATE_AUTH CONFIG_DROPBEAR_USE_PASSWORD_ENV CONFIG_DROPBEAR_CLI_ASKPASS_HELPER CONFIG_DROPBEAR_CLI_AGENTFWD CONFIG_DROPBEAR_CLI_LOCALTCPFWD CONFIG_DROPBEAR_CLI_REMOTETCPFWD CONFIG_DROPBEAR_CLI_PROXYCMD CONFIG_DROPBEAR_CLI_NETCAT CONFIG_DROPBEAR_CLI_MULTIHOP \
CONFIG_DROPBEAR_KEX_REKEY_TIMEOUT CONFIG_DROPBEAR_KEX_REKEY_DATA CONFIG_DROPBEAR_AUTH_TIMEOUT CONFIG_DROPBEAR_MAX_AUTH_TRIES CONFIG_DROPBEAR_UNAUTH_CLOSE_DELAY CONFIG_DROPBEAR_MAX_UNAUTH_PER_IP CONFIG_DROPBEAR_MAX_UNAUTH_CLIENTS CONFIG_DROPBEAR_DEFAULT_RECV_WINDOW CONFIG_DROPBEAR_DEFAULT_KEEPALIVE CONFIG_DROPBEAR_DEFAULT_KEEPALIVE_LIMIT CONFIG_DROPBEAR_DEFAULT_IDLE_TIMEOUT \
CONFIG_DROPBEAR_KEX_REKEY_TIMEOUT CONFIG_DROPBEAR_KEX_REKEY_DATA CONFIG_DROPBEAR_AUTH_TIMEOUT CONFIG_DROPBEAR_MAX_AUTH_TRIES CONFIG_DROPBEAR_UNAUTH_CLOSE_DELAY CONFIG_DROPBEAR_MAX_UNAUTH_PER_IP CONFIG_DROPBEAR_MAX_UNAUTH_CLIENTS CONFIG_DROPBEAR_DEFAULT_RECV_WINDOW CONFIG_DROPBEAR_DEFAULT_KEEPALIVE CONFIG_DROPBEAR_DEFAULT_KEEPALIVE_LIMIT CONFIG_DROPBEAR_DEFAULT_IDLE_TIMEOUT CONFIG_DROPBEAR_MAX_PUBKEY_QUERIES CONFIG_DROPBEAR_DEFAULT_MAX_DURATION \
CONFIG_DROPBEAR_3DES CONFIG_DROPBEAR_AES128 CONFIG_DROPBEAR_AES256 CONFIG_DROPBEAR_CHACHA20POLY1305 \
CONFIG_DROPBEAR_ENABLE_CTR_MODE CONFIG_DROPBEAR_ENABLE_CBC_MODE CONFIG_DROPBEAR_ENABLE_GCM_MODE \
CONFIG_DROPBEAR_SHA1_96_HMAC CONFIG_DROPBEAR_SHA1_HMAC CONFIG_DROPBEAR_SHA2_256_HMAC CONFIG_DROPBEAR_SHA2_512_HMAC \
@@ -130,10 +130,12 @@ DB_OPT_COMMON = \
DEFAULT_IDLE_TIMEOUT,$(CONFIG_DROPBEAR_DEFAULT_IDLE_TIMEOUT) \
DEFAULT_KEEPALIVE_LIMIT,$(CONFIG_DROPBEAR_DEFAULT_KEEPALIVE_LIMIT) \
DEFAULT_KEEPALIVE,$(CONFIG_DROPBEAR_DEFAULT_KEEPALIVE) \
DEFAULT_MAX_DURATION,$(CONFIG_DROPBEAR_DEFAULT_MAX_DURATION) \
DEFAULT_RECV_WINDOW,$(CONFIG_DROPBEAR_DEFAULT_RECV_WINDOW) \
KEX_REKEY_DATA,$(CONFIG_DROPBEAR_KEX_REKEY_DATA) \
KEX_REKEY_TIMEOUT,$(CONFIG_DROPBEAR_KEX_REKEY_TIMEOUT) \
MAX_AUTH_TRIES,$(CONFIG_DROPBEAR_MAX_AUTH_TRIES) \
MAX_PUBKEY_QUERIES,$(CONFIG_DROPBEAR_MAX_PUBKEY_QUERIES) \
MAX_UNAUTH_CLIENTS,$(CONFIG_DROPBEAR_MAX_UNAUTH_CLIENTS) \
MAX_UNAUTH_PER_IP,$(CONFIG_DROPBEAR_MAX_UNAUTH_PER_IP) \
UNAUTH_CLOSE_DELAY,$(CONFIG_DROPBEAR_UNAUTH_CLOSE_DELAY) \
@@ -1,61 +1,83 @@
#!/bin/sh
_dropbear()
{
/usr/sbin/dropbear "$@" </dev/null >/dev/null 2>&1
db_key_quiet() { dropbearkey "$@" </dev/null >/dev/null 2>&1 ; }
db_key_types_int() {
dropbearkey -h </dev/null 2>&1 \
| sed -En '/^\s*-t/,/^\s*-/p' \
| sed -En '/^\s*-/n;p'
}
db_key_types() {
normalize_list "$(db_key_types_int)"
}
_dropbearkey()
db_key_ensure()
{
/usr/bin/dropbearkey "$@" </dev/null >/dev/null 2>&1
}
_ensurekey()
{
_dropbearkey -y -f "$1" && return
db_key_quiet -y -f "$1" && return
rm -f "$1"
_dropbearkey -f "$@" || {
db_key_quiet -f "$@" || {
rm -f "$1"
return 1
}
}
ktype_all='ed25519 ecdsa rsa'
# $1 - list with whitespace-separated elements
normalize_list()
{
printf '%s' "$1" | tr -s ' \r\n\t' ' ' | sed -E 's/^ //;s/ $//'
}
failsafe_dropbear () {
local kargs kcount ktype tkey
failsafe_dropbear() {
local ktype_all kargs kcount ktype tkey
# don't hardcode supported algorithm list until things go wrong
ktype_all=$(db_key_types)
[ -n "${ktype_all}" ] || {
echo "dropbear: unable to correctly retrieve supported hostkey algorithms!" >&2
ktype_all='rsa ecdsa ed25519'
}
kargs=
kcount=0
for ktype in ${ktype_all} ; do
tkey="/tmp/dropbear_failsafe_${ktype}_host_key"
case "${ktype}" in
ed25519) _ensurekey "${tkey}" -t ed25519 ;;
ecdsa) _ensurekey "${tkey}" -t ecdsa -s 256 ;;
rsa) _ensurekey "${tkey}" -t rsa -s 1024 ;;
*)
echo "unknown key type: ${ktype}" >&2
continue
rsa ) ;; # skip (see below)
* )
tkey="/tmp/dropbear_failsafe_${ktype}_host_key"
db_key_ensure "${tkey}" -t "${ktype}" || :
if [ -s "${tkey}" ] ; then
chmod 0400 "${tkey}"
kargs="${kargs} -r ${tkey}"
kcount=$((kcount+1))
else
rm -f "${tkey}" "${tkey}.pub"
fi
;;
esac
[ -s "${tkey}" ] || {
rm -f "${tkey}"
continue
}
chmod 0400 "${tkey}"
kargs="${kargs}${kargs:+ }-r ${tkey}"
kcount=$((kcount+1))
done
# use RSA only if none of the modern algorithms is supported
if [ "${kcount}" = 0 ] ; then
ktype=rsa
tkey="/tmp/dropbear_failsafe_${ktype}_host_key"
db_key_ensure "${tkey}" -t "${ktype}" || :
if [ -s "${tkey}" ] ; then
chmod 0400 "${tkey}"
kargs="${kargs} -r ${tkey}"
kcount=$((kcount+1))
else
rm -f "${tkey}" "${tkey}.pub"
fi
fi
[ "${kcount}" != 0 ] || {
echo 'DROPBEAR IS BROKEN' >&2
return 1
}
_dropbear ${kargs}
dropbear ${kargs} </dev/null >/dev/null 2>&1
}
boot_hook_add failsafe failsafe_dropbear
@@ -18,9 +18,14 @@ dumb_stat() { ls -Ldln "$1" | tr -s '\t ' ' ' ; }
stat_perm() { real_stat -c '%A' "$1" || dumb_stat "$1" | cut -d ' ' -f 1 ; }
stat_owner() { real_stat -c '%u' "$1" || dumb_stat "$1" | cut -d ' ' -f 3 ; }
_dropbearkey()
{
/usr/bin/dropbearkey "$@" </dev/null >/dev/null 2>&1
db_key_quiet() { dropbearkey "$@" </dev/null >/dev/null 2>&1 ; }
db_key_types_int() {
dropbearkey -h </dev/null 2>&1 \
| sed -En '/^\s*-t/,/^\s*-/p' \
| sed -En '/^\s*-/n;p'
}
db_key_types() {
normalize_list "$(db_key_types_int)"
}
# $1 - file name (host key or config)
@@ -43,7 +48,7 @@ file_verify()
[ -z "$2" ] || return 0
# checking file contents (finally)
[ -s "$1" ] || return 4
_dropbearkey -y -f "$1" || return 5
db_key_quiet -y -f "$1" || return 5
return 0
}
@@ -79,22 +84,32 @@ hk_config()
# $1 - host key file name
hk_config__keyfile() { hk_config keyfile "$1" ; }
ktype_all='ed25519 ecdsa rsa'
hk_generate_as_needed()
{
local hk_cfg_dir kgen ktype kfile hk_tmp_dir
local hk_cfg_dir ktype_all kgen ktype kfile hk_tmp_dir
hk_cfg_dir='/etc/dropbear'
[ -d "${hk_cfg_dir}" ] || mkdir -p "${hk_cfg_dir}"
# don't hardcode supported algorithm list until things go wrong
ktype_all=$(db_key_types)
[ -n "${ktype_all}" ] || {
logger -t "${NAME}" -p daemon.warn \
"unable to correctly retrieve supported hostkey algorithms!"
ktype_all='rsa ecdsa ed25519'
}
kgen=
for ktype in ${ktype_all} ; do
kfile="${hk_cfg_dir}/dropbear_${ktype}_host_key"
if file_verify "${kfile}" ; then continue ; fi
kgen="${kgen}${kgen:+ }${ktype}"
# cleanup empty files (if any)
[ -s "${kfile}" ] || rm -f "${kfile}"
kgen="${kgen} ${ktype}"
done
# all keys are sane?
@@ -103,28 +118,27 @@ hk_generate_as_needed()
hk_tmp_dir=$(mktemp -d)
# system in bad state?
[ -n "${hk_tmp_dir}" ] || return 1
chmod 0700 "${hk_tmp_dir}"
for ktype in ${kgen} ; do
kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
if ! _dropbearkey -t ${ktype} -f "${kfile}" ; then
if ! db_key_quiet -t "${ktype}" -f "${kfile}" ; then
# unsupported key type
rm -f "${kfile}"
rm -f "${kfile}" "${kfile}.pub"
continue
fi
chmod 0600 "${kfile}"
# unused file
rm -f "${kfile}.pub"
done
kgen=
for ktype in ${ktype_all} ; do
kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
[ -s "${kfile}" ] || continue
kgen="${kgen}${kgen:+ }${ktype}"
kgen="${kgen} ${ktype}"
done
if [ -n "${kgen}" ] ; then
@@ -136,13 +150,6 @@ hk_generate_as_needed()
fi
rm -rf "${hk_tmp_dir}"
# cleanup empty files
for ktype in ${ktype_all} ; do
kfile="${hk_cfg_dir}/dropbear_${ktype}_host_key"
[ -s "${kfile}" ] || rm -f "${kfile}"
done
}
# $1 - list with whitespace-separated elements
@@ -176,6 +183,7 @@ validate_section_dropbear()
'Port:port:22' \
'SSHKeepAlive:uinteger:300' \
'IdleTimeout:uinteger:0' \
'MaxSessionDuration:uinteger:0' \
'MaxAuthTries:uinteger:3' \
'RecvWindowSize:uinteger:0' \
'LocalPortForward:bool:1' \
@@ -336,6 +344,7 @@ dropbear_instance()
fi
[ -n "${BannerFile}" ] && procd_append_param command -b "${BannerFile}"
[ "${IdleTimeout}" -ne 0 ] && procd_append_param command -I "${IdleTimeout}"
[ "${MaxSessionDuration}" -ne 0 ] && procd_append_param command -M "${MaxSessionDuration}"
[ "${SSHKeepAlive}" -ne 0 ] && procd_append_param command -K "${SSHKeepAlive}"
[ "${MaxAuthTries}" -ne 0 ] && procd_append_param command -T "${MaxAuthTries}"
[ "${RecvWindowSize}" -gt 0 ] && {
@@ -0,0 +1,27 @@
From b487b111d0cf735c640e6668aa888f7da4e78b3c Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 11 May 2026 20:43:50 +0800
Subject: sntrup: Fix 64-bit literals
Avoids warning on 32-bit platform
src/sntrup761.c:1643: warning: integer constant is too large for 'long' type
---
src/sntrup761.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/src/sntrup761.c
+++ b/src/sntrup761.c
@@ -1640,9 +1640,9 @@ __attribute__((unused))
static inline
int crypto_int64_ones_num(crypto_int64 crypto_int64_x) {
crypto_int64_unsigned crypto_int64_y = crypto_int64_x;
- const crypto_int64 C0 = 0x5555555555555555;
- const crypto_int64 C1 = 0x3333333333333333;
- const crypto_int64 C2 = 0x0f0f0f0f0f0f0f0f;
+ const crypto_int64 C0 = INT64_C(0x5555555555555555);
+ const crypto_int64 C1 = INT64_C(0x3333333333333333);
+ const crypto_int64 C2 = INT64_C(0x0f0f0f0f0f0f0f0f);
crypto_int64_y -= ((crypto_int64_y >> 1) & C0);
crypto_int64_y = (crypto_int64_y & C1) + ((crypto_int64_y >> 2) & C1);
crypto_int64_y = (crypto_int64_y + (crypto_int64_y >> 4)) & C2;
@@ -0,0 +1,23 @@
From a05569c6124006bd9b4823db30e824953c5024de Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Wed, 13 May 2026 08:40:17 +0800
Subject: Increase MAX_HOSTKEYS to 6
This allows all key types to be loaded at once, including different
ecdsa sizes.
Suggested by Darren Tucker.
---
src/sysoptions.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/src/sysoptions.h
+++ b/src/sysoptions.h
@@ -283,7 +283,7 @@
#define MAX_KEX_PARTS 1000
#endif
-#define MAX_HOSTKEYS 4
+#define MAX_HOSTKEYS 6
/* The maximum size of the bignum portion of the kexhash buffer */
/* K_S + Q_C + Q_S + K */
@@ -0,0 +1,33 @@
From ee65bff1567576a223febcdd5ae552326a4da4b1 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 19 May 2026 19:03:39 +0800
Subject: Fix too-low pubkey key query count
Dropbear 2026.90 added a limit to the number of queries that could be
made to a server when determining usable keys. This was intended to be
set to 15 (MAX_PUBKEY_QUERIES) but the logic was incorrect (and also
debug code was accidentally committed). This meant only 10 (default
MAX_AUTH_TRIES/-T) tried keys would be allowed - not a huge difference.
Reported by Rui Salvaterra
Fixes: db0d3fd0a9e9 ("Limit server number of public key queries")
---
src/svr-authpubkey.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/src/svr-authpubkey.c
+++ b/src/svr-authpubkey.c
@@ -173,9 +173,9 @@ void svr_auth_pubkey(int valid_user) {
* Start counting failures (incrfail) only when it's reaching
* the limit.
*/
- unsigned int free_query_limit = 0;
- MAX(0, (int)svr_opts.maxauthtries - MAX_PUBKEY_QUERIES);
- int incrfail = ses.authstate.serv_pubkey_query_count > free_query_limit;
+ unsigned int free_query_limit =
+ MAX(0, MAX_PUBKEY_QUERIES - (int)svr_opts.maxauthtries);
+ int incrfail = ses.authstate.serv_pubkey_query_count >= free_query_limit;
send_msg_userauth_failure(0, incrfail);
ses.authstate.serv_pubkey_query_count++;
goto out;
@@ -3,7 +3,7 @@
--- a/src/svr-authpubkey.c
+++ b/src/svr-authpubkey.c
@@ -79,6 +79,39 @@ static void send_msg_userauth_pk_ok(cons
@@ -80,6 +80,39 @@ static void send_msg_userauth_pk_ok(cons
const unsigned char* keyblob, unsigned int keybloblen);
static int checkfileperm(char * filename);
@@ -43,7 +43,7 @@
/* process a pubkey auth request, sending success or failure message as
* appropriate */
void svr_auth_pubkey(int valid_user) {
@@ -439,16 +472,22 @@ out:
@@ -459,16 +492,22 @@ out:
static char *authorized_keys_filepath() {
size_t len = 0;
char *pathname = NULL, *dir = NULL;
@@ -69,7 +69,7 @@
m_free(dir);
return pathname;
}
@@ -549,11 +588,23 @@ out:
@@ -572,11 +611,23 @@ out:
* When this path is inside the user's home dir it checks up to and including
* the home dir, otherwise it checks every path component. */
static int checkpubkeyperms() {
@@ -1,6 +1,6 @@
--- a/src/svr-auth.c
+++ b/src/svr-auth.c
@@ -510,9 +510,9 @@ void svr_switch_user(void) {
@@ -504,9 +504,9 @@ void svr_switch_user(void) {
/* We can only change uid/gid as root ... */
if (getuid() == 0) {
@@ -12,7 +12,7 @@
dropbear_exit("Error changing user group");
}
@@ -534,7 +534,7 @@ void svr_switch_user(void) {
@@ -528,7 +528,7 @@ void svr_switch_user(void) {
}
#endif
@@ -1,6 +1,6 @@
--- a/src/cli-runopts.c
+++ b/src/cli-runopts.c
@@ -340,6 +340,10 @@ void cli_getopts(int argc, char ** argv)
@@ -352,6 +352,10 @@ void cli_getopts(int argc, char ** argv)
case 'z':
opts.disable_ip_tos = 1;
break;
@@ -1,6 +1,6 @@
--- a/src/svr-auth.c
+++ b/src/svr-auth.c
@@ -124,7 +124,7 @@ void recv_msg_userauth_request() {
@@ -122,7 +122,7 @@ void recv_msg_userauth_request() {
AUTH_METHOD_NONE_LEN) == 0) {
TRACE(("recv_msg_userauth_request: 'none' request"))
if (valid_user
+2 -2
View File
@@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=lldpd
PKG_VERSION:=1.0.20
PKG_VERSION:=1.0.22
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/lldpd/lldpd/releases/download/$(PKG_VERSION)/
PKG_HASH:=c851ce102444b932b691f0d00142520333030822709fc4566ef20c651ae1714f
PKG_HASH:=552baa55118bccbcd1e61c51db438930a36ce04e0abd84c4c0b7b20633ca2b5a
PKG_MAINTAINER:=Stijn Tintel <stijn@linux-ipv6.be>
PKG_LICENSE:=ISC
+3 -3
View File
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_URL=$(PROJECT_GIT)/project/ustp.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2023-05-29
PKG_SOURCE_VERSION:=a85a5bc83bde5b485319ca12b6e32c4b7f0b120f
PKG_MIRROR_HASH:=b907b91989320eb8916e719ced9bdce96b8c5db6abefcee35e25fb112ad5b27f
PKG_SOURCE_DATE:=2026-05-27
PKG_SOURCE_VERSION:=17c36bebada116b98784a6a17412005537bdf8ac
PKG_MIRROR_HASH:=04498fb8886082dd78bb11bda5e05fbbe6aacb4dc782f425bbdb193fbbc54620
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0
+3 -3
View File
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ethtool
PKG_VERSION:=6.19
PKG_RELEASE:=2
PKG_VERSION:=7.0
PKG_RELEASE:=1
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=@KERNEL/software/network/ethtool
PKG_HASH:=1c2114ab6e0c0d2aa67d699960eb11df4f341e2403139cdf28ae9da858a6025f
PKG_HASH:=660bf9725a7871343a0d232068a7634fbcfb69b6c2f8eff455827faefb0cd162
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING
+4
View File
@@ -242,6 +242,10 @@ int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)
mtdofs = ofs;
buf = malloc(erasesize);
if (!buf) {
fprintf(stderr, "Out of memory!\n");
return -1;
}
target_ino = 1;
if (!last_ino)
last_ino = 1;
-18
View File
@@ -79,32 +79,14 @@ CONFIG_CPU_MITIGATIONS=y
CONFIG_CPU_RMAP=y
CONFIG_CRC16=y
CONFIG_CRC_CCITT=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_DRBG_HMAC=y
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_GENIV=y
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_JITTERENTROPY=y
CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS=64
CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE=32
CONFIG_CRYPTO_JITTERENTROPY_OSR=1
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG_DEFAULT=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA3=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_ZSTD=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_INFO=y
-12
View File
@@ -84,26 +84,14 @@ CONFIG_CRC_CCITT=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_DEV_EIP93=y
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_DRBG_HMAC=y
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_JITTERENTROPY=y
CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS=64
CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE=32
CONFIG_CRYPTO_JITTERENTROPY_OSR=1
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG_DEFAULT=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA3=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_ZSTD=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_MISC=y
@@ -174,33 +174,51 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
} else { /* scattered frame */
struct skb_shared_info *shinfo = skb_shinfo(q->skb);
int nr_frags = shinfo->nr_frags;
@@ -743,12 +869,13 @@ static int airoha_qdma_rx_napi_poll(stru
@@ -743,12 +869,10 @@ static int airoha_qdma_rx_napi_poll(stru
static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
struct airoha_qdma *qdma, int ndesc)
{
+ int pp_order = airoha_qdma_is_lro_queue(q) ? AIROHA_LRO_PAGE_ORDER : 0;
const struct page_pool_params pp_params = {
- const struct page_pool_params pp_params = {
- .order = 0,
+ .order = pp_order,
+ struct page_pool_params pp_params = {
.pool_size = 256,
.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
.dma_dir = DMA_FROM_DEVICE,
- .max_len = PAGE_SIZE,
+ .max_len = PAGE_SIZE << pp_order,
.nid = NUMA_NO_NODE,
.dev = qdma->eth->dev,
.napi = &q->napi,
@@ -757,7 +884,8 @@ static int airoha_qdma_init_rx_queue(str
@@ -756,9 +880,10 @@ static int airoha_qdma_init_rx_queue(str
struct airoha_eth *eth = qdma->eth;
int qid = q - &qdma->q_rx[0], thr;
dma_addr_t dma_addr;
+ bool lro_q;
- q->buf_size = PAGE_SIZE / 2;
+ q->buf_size = airoha_qdma_is_lro_queue(q) ? pp_params.max_len
+ : pp_params.max_len / 2;
q->qdma = qdma;
+ lro_q = airoha_qdma_is_lro_queue(q);
q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry),
@@ -2034,6 +2162,67 @@ int airoha_get_fe_port(struct airoha_gdm
GFP_KERNEL);
@@ -770,6 +895,9 @@ static int airoha_qdma_init_rx_queue(str
if (!q->desc)
return -ENOMEM;
+ pp_params.order = lro_q ? AIROHA_LRO_PAGE_ORDER : 0;
+ pp_params.max_len = PAGE_SIZE << pp_params.order;
+
q->page_pool = page_pool_create(&pp_params);
if (IS_ERR(q->page_pool)) {
int err = PTR_ERR(q->page_pool);
@@ -778,6 +906,7 @@ static int airoha_qdma_init_rx_queue(str
return err;
}
+ q->buf_size = lro_q ? pp_params.max_len : pp_params.max_len / 2;
q->ndesc = ndesc;
netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
@@ -2034,6 +2163,67 @@ int airoha_get_fe_port(struct airoha_gdm
}
}
@@ -268,7 +286,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -2933,6 +3122,7 @@ static const struct net_device_ops airoh
@@ -2933,6 +3123,7 @@ static const struct net_device_ops airoh
.ndo_stop = airoha_dev_stop,
.ndo_change_mtu = airoha_dev_change_mtu,
.ndo_select_queue = airoha_dev_select_queue,
@@ -276,7 +294,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
.ndo_start_xmit = airoha_dev_xmit,
.ndo_get_stats64 = airoha_dev_get_stats64,
.ndo_set_mac_address = airoha_dev_set_macaddr,
@@ -3150,12 +3340,9 @@ static int airoha_alloc_gdm_port(struct
@@ -3150,12 +3341,9 @@ static int airoha_alloc_gdm_port(struct
dev->ethtool_ops = &airoha_ethtool_ops;
dev->max_mtu = AIROHA_MAX_MTU;
dev->watchdog_timeo = 5 * HZ;
@@ -70,7 +70,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
/* PPE module requires untagged packets to work
* properly and it provides DSA port index via the
* DMA descriptor. Report DSA tag to the DSA stack
@@ -992,6 +997,7 @@ static void airoha_qdma_wake_netdev_txqs
@@ -993,6 +998,7 @@ static void airoha_qdma_wake_netdev_txqs
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -78,7 +78,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
int j;
if (!port)
@@ -1000,11 +1006,12 @@ static void airoha_qdma_wake_netdev_txqs
@@ -1001,11 +1007,12 @@ static void airoha_qdma_wake_netdev_txqs
if (port->qdma != qdma)
continue;
@@ -93,7 +93,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
}
q->txq_stopped = false;
@@ -1848,33 +1855,34 @@ static void airoha_update_hw_stats(struc
@@ -1849,33 +1856,34 @@ static void airoha_update_hw_stats(struc
spin_unlock(&port->stats.lock);
}
@@ -136,7 +136,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
else
@@ -1902,16 +1910,17 @@ static int airoha_dev_open(struct net_de
@@ -1903,16 +1911,17 @@ static int airoha_dev_open(struct net_de
return 0;
}
@@ -159,7 +159,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id),
FE_PSE_PORT_DROP);
@@ -1931,24 +1940,25 @@ static int airoha_dev_stop(struct net_de
@@ -1932,24 +1941,25 @@ static int airoha_dev_stop(struct net_de
#if defined(CONFIG_PCS_AIROHA)
if (airhoa_is_phy_external(port)) {
@@ -191,7 +191,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
return 0;
}
@@ -2014,16 +2024,17 @@ static int airoha_set_gdm2_loopback(stru
@@ -2015,16 +2025,17 @@ static int airoha_set_gdm2_loopback(stru
return 0;
}
@@ -214,7 +214,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
switch (port->id) {
case AIROHA_GDM3_IDX:
@@ -2048,10 +2059,11 @@ static int airoha_dev_init(struct net_de
@@ -2049,10 +2060,11 @@ static int airoha_dev_init(struct net_de
return 0;
}
@@ -228,7 +228,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
unsigned int start;
airoha_update_hw_stats(port);
@@ -2070,36 +2082,39 @@ static void airoha_dev_get_stats64(struc
@@ -2071,36 +2083,39 @@ static void airoha_dev_get_stats64(struc
} while (u64_stats_fetch_retry(&port->stats.syncp, start));
}
@@ -275,7 +275,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
static u32 airoha_get_dsa_tag(struct sk_buff *skb, struct net_device *dev)
@@ -2162,11 +2177,12 @@ int airoha_get_fe_port(struct airoha_gdm
@@ -2163,11 +2178,12 @@ int airoha_get_fe_port(struct airoha_gdm
}
}
@@ -291,7 +291,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
struct airoha_qdma *qdma = port->qdma;
struct airoha_eth *eth = qdma->eth;
int qdma_id = qdma - &eth->qdma[0];
@@ -2175,7 +2191,7 @@ static int airoha_dev_set_features(struc
@@ -2176,7 +2192,7 @@ static int airoha_dev_set_features(struc
if (!(diff & NETIF_F_LRO))
return 0;
@@ -300,7 +300,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
return -EBUSY;
/* reset LRO configuration */
@@ -2204,6 +2220,7 @@ static int airoha_dev_set_features(struc
@@ -2205,6 +2221,7 @@ static int airoha_dev_set_features(struc
} else {
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *p = eth->ports[i];
@@ -308,7 +308,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (!p)
continue;
@@ -2211,10 +2228,11 @@ static int airoha_dev_set_features(struc
@@ -2212,10 +2229,11 @@ static int airoha_dev_set_features(struc
if (p->qdma != qdma)
continue;
@@ -322,7 +322,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
return 0;
}
airoha_fe_lro_disable(eth, qdma_id);
@@ -2224,9 +2242,10 @@ static int airoha_dev_set_features(struc
@@ -2225,9 +2243,10 @@ static int airoha_dev_set_features(struc
}
static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
@@ -335,7 +335,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
struct airoha_qdma *qdma = port->qdma;
u32 nr_frags, tag, msg0, msg1, len;
struct airoha_queue_entry *e;
@@ -2239,7 +2258,7 @@ static netdev_tx_t airoha_dev_xmit(struc
@@ -2240,7 +2259,7 @@ static netdev_tx_t airoha_dev_xmit(struc
u8 fport;
qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb));
@@ -344,7 +344,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK,
qid / AIROHA_NUM_QOS_QUEUES) |
@@ -2275,7 +2294,7 @@ static netdev_tx_t airoha_dev_xmit(struc
@@ -2276,7 +2295,7 @@ static netdev_tx_t airoha_dev_xmit(struc
spin_lock_bh(&q->lock);
@@ -353,7 +353,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
nr_frags = 1 + skb_shinfo(skb)->nr_frags;
if (q->queued + nr_frags >= q->ndesc) {
@@ -2299,9 +2318,9 @@ static netdev_tx_t airoha_dev_xmit(struc
@@ -2300,9 +2319,9 @@ static netdev_tx_t airoha_dev_xmit(struc
dma_addr_t addr;
u32 val;
@@ -365,7 +365,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
goto error_unmap;
list_move_tail(&e->list, &tx_list);
@@ -2350,7 +2369,7 @@ static netdev_tx_t airoha_dev_xmit(struc
@@ -2351,7 +2370,7 @@ static netdev_tx_t airoha_dev_xmit(struc
error_unmap:
list_for_each_entry(e, &tx_list, list) {
@@ -374,7 +374,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
DMA_TO_DEVICE);
e->dma_addr = 0;
}
@@ -2359,25 +2378,27 @@ error_unmap:
@@ -2360,25 +2379,27 @@ error_unmap:
spin_unlock_bh(&q->lock);
error:
dev_kfree_skb_any(skb);
@@ -407,7 +407,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
unsigned int start;
airoha_update_hw_stats(port);
@@ -2405,11 +2426,12 @@ static const struct ethtool_rmon_hist_ra
@@ -2406,11 +2427,12 @@ static const struct ethtool_rmon_hist_ra
};
static void
@@ -422,7 +422,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
struct airoha_hw_stats *hw_stats = &port->stats;
unsigned int start;
@@ -2434,11 +2456,12 @@ airoha_ethtool_get_rmon_stats(struct net
@@ -2435,11 +2457,12 @@ airoha_ethtool_get_rmon_stats(struct net
} while (u64_stats_fetch_retry(&port->stats.syncp, start));
}
@@ -437,7 +437,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
int i;
for (i = 0; i < AIROHA_NUM_TX_RING; i++)
@@ -2523,10 +2546,12 @@ static int airoha_qdma_set_tx_ets_sched(
@@ -2524,10 +2547,12 @@ static int airoha_qdma_set_tx_ets_sched(
ARRAY_SIZE(w));
}
@@ -452,7 +452,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u64 cpu_tx_packets = airoha_qdma_rr(port->qdma,
REG_CNTR_VAL(channel << 1));
u64 fwd_tx_packets = airoha_qdma_rr(port->qdma,
@@ -2788,11 +2813,12 @@ static int airoha_qdma_set_trtcm_token_b
@@ -2789,11 +2814,12 @@ static int airoha_qdma_set_trtcm_token_b
mode, val);
}
@@ -467,7 +467,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
int i, err;
for (i = 0; i <= TRTCM_PEAK_MODE; i++) {
@@ -2812,20 +2838,22 @@ static int airoha_qdma_set_tx_rate_limit
@@ -2813,20 +2839,22 @@ static int airoha_qdma_set_tx_rate_limit
return 0;
}
@@ -494,7 +494,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (err) {
NL_SET_ERR_MSG_MOD(opt->extack,
"failed configuring htb offload");
@@ -2835,9 +2863,10 @@ static int airoha_tc_htb_alloc_leaf_queu
@@ -2836,9 +2864,10 @@ static int airoha_tc_htb_alloc_leaf_queu
if (opt->command == TC_HTB_NODE_MODIFY)
return 0;
@@ -507,7 +507,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
NL_SET_ERR_MSG_MOD(opt->extack,
"failed setting real_num_tx_queues");
return err;
@@ -2927,11 +2956,12 @@ static int airoha_tc_matchall_act_valida
@@ -2928,11 +2957,12 @@ static int airoha_tc_matchall_act_valida
return 0;
}
@@ -522,7 +522,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 rate = 0, bucket_size = 0;
switch (f->command) {
@@ -2966,18 +2996,19 @@ static int airoha_dev_tc_matchall(struct
@@ -2967,18 +2997,19 @@ static int airoha_dev_tc_matchall(struct
static int airoha_dev_setup_tc_block_cb(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
@@ -546,7 +546,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
default:
return -EOPNOTSUPP;
}
@@ -3024,47 +3055,51 @@ static int airoha_dev_setup_tc_block(str
@@ -3025,47 +3056,51 @@ static int airoha_dev_setup_tc_block(str
}
}
@@ -610,7 +610,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (!test_bit(channel, port->qos_sq_bmap)) {
NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
@@ -3100,8 +3135,8 @@ static int airoha_tc_setup_qdisc_htb(str
@@ -3101,8 +3136,8 @@ static int airoha_tc_setup_qdisc_htb(str
return 0;
}
@@ -621,7 +621,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
{
switch (type) {
case TC_SETUP_QDISC_ETS:
@@ -3173,13 +3208,18 @@ static void airoha_metadata_dst_free(str
@@ -3174,13 +3209,18 @@ static void airoha_metadata_dst_free(str
}
}
@@ -643,7 +643,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
return true;
}
@@ -3191,8 +3231,9 @@ static void airoha_mac_link_up(struct ph
@@ -3192,8 +3232,9 @@ static void airoha_mac_link_up(struct ph
unsigned int mode, phy_interface_t interface,
int speed, int duplex, bool tx_pause, bool rx_pause)
{
@@ -655,7 +655,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
struct airoha_qdma *qdma = port->qdma;
struct airoha_eth *eth = qdma->eth;
u32 frag_size_tx, frag_size_rx;
@@ -3248,65 +3289,122 @@ static int airoha_fill_available_pcs(str
@@ -3249,65 +3290,122 @@ static int airoha_fill_available_pcs(str
&num_available_pcs);
}
@@ -800,7 +800,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
int err, p;
u32 id;
@@ -3328,58 +3426,22 @@ static int airoha_alloc_gdm_port(struct
@@ -3329,58 +3427,22 @@ static int airoha_alloc_gdm_port(struct
return -EINVAL;
}
@@ -865,7 +865,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
static int airoha_register_gdm_devices(struct airoha_eth *eth)
@@ -3393,7 +3455,7 @@ static int airoha_register_gdm_devices(s
@@ -3394,7 +3456,7 @@ static int airoha_register_gdm_devices(s
if (!port)
continue;
@@ -874,7 +874,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (err)
return err;
}
@@ -3502,16 +3564,18 @@ error_napi_stop:
@@ -3503,16 +3565,18 @@ error_napi_stop:
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -896,7 +896,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
airoha_metadata_dst_free(port);
}
@@ -3533,15 +3597,19 @@ static void airoha_remove(struct platfor
@@ -3534,15 +3598,19 @@ static void airoha_remove(struct platfor
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -60,7 +60,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 vip_port;
vip_port = eth->soc->ops.get_vip_port(port, port->nbq);
@@ -1003,10 +1004,13 @@ static void airoha_qdma_wake_netdev_txqs
@@ -1004,10 +1005,13 @@ static void airoha_qdma_wake_netdev_txqs
if (!port)
continue;
@@ -76,7 +76,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
for (j = 0; j < dev->dev->num_tx_queues; j++) {
if (airoha_qdma_get_txq(qdma, j) != qid)
continue;
@@ -1711,9 +1715,10 @@ static void airoha_qdma_stop_napi(struct
@@ -1712,9 +1716,10 @@ static void airoha_qdma_stop_napi(struct
}
}
@@ -89,7 +89,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 val, i = 0;
spin_lock(&port->stats.lock);
@@ -1860,7 +1865,7 @@ static int airoha_dev_open(struct net_de
@@ -1861,7 +1866,7 @@ static int airoha_dev_open(struct net_de
int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
@@ -98,7 +98,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 pse_port = FE_PSE_PORT_PPE1;
#if defined(CONFIG_PCS_AIROHA)
@@ -1877,7 +1882,7 @@ static int airoha_dev_open(struct net_de
@@ -1878,7 +1883,7 @@ static int airoha_dev_open(struct net_de
#endif
netif_tx_start_all_queues(netdev);
@@ -107,7 +107,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (err)
return err;
@@ -1914,11 +1919,11 @@ static int airoha_dev_stop(struct net_de
@@ -1915,11 +1920,11 @@ static int airoha_dev_stop(struct net_de
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
@@ -121,7 +121,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
for (i = 0; i < netdev->num_tx_queues; i++)
netdev_tx_reset_subqueue(netdev, i);
@@ -1951,21 +1956,21 @@ static int airoha_dev_stop(struct net_de
@@ -1952,21 +1957,21 @@ static int airoha_dev_stop(struct net_de
static int airoha_dev_set_macaddr(struct net_device *netdev, void *p)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -147,7 +147,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 val, pse_port, chan;
int i, src_port;
@@ -2012,7 +2017,7 @@ static int airoha_set_gdm2_loopback(stru
@@ -2013,7 +2018,7 @@ static int airoha_set_gdm2_loopback(stru
__field_prep(SP_CPORT_MASK(val), FE_PSE_PORT_CDM2));
for (i = 0; i < eth->soc->num_ppe; i++)
@@ -156,7 +156,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) {
u32 mask = FC_ID_OF_SRC_PORT_MASK(port->nbq);
@@ -2032,9 +2037,9 @@ static int airoha_dev_init(struct net_de
@@ -2033,9 +2038,9 @@ static int airoha_dev_init(struct net_de
int i;
/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */
@@ -169,7 +169,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
switch (port->id) {
case AIROHA_GDM3_IDX:
@@ -2043,7 +2048,7 @@ static int airoha_dev_init(struct net_de
@@ -2044,7 +2049,7 @@ static int airoha_dev_init(struct net_de
if (!eth->ports[1]) {
int err;
@@ -178,7 +178,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (err)
return err;
}
@@ -2053,8 +2058,7 @@ static int airoha_dev_init(struct net_de
@@ -2054,8 +2059,7 @@ static int airoha_dev_init(struct net_de
}
for (i = 0; i < eth->soc->num_ppe; i++)
@@ -188,7 +188,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
return 0;
}
@@ -2066,7 +2070,7 @@ static void airoha_dev_get_stats64(struc
@@ -2067,7 +2071,7 @@ static void airoha_dev_get_stats64(struc
struct airoha_gdm_port *port = dev->port;
unsigned int start;
@@ -197,7 +197,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
do {
start = u64_stats_fetch_begin(&port->stats.syncp);
storage->rx_packets = port->stats.rx_ok_pkts;
@@ -2086,8 +2090,8 @@ static int airoha_dev_change_mtu(struct
@@ -2087,8 +2091,8 @@ static int airoha_dev_change_mtu(struct
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
@@ -207,7 +207,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id),
GDM_LONG_LEN_MASK,
@@ -2161,10 +2165,10 @@ static u32 airoha_get_dsa_tag(struct sk_
@@ -2162,10 +2166,10 @@ static u32 airoha_get_dsa_tag(struct sk_
#endif
}
@@ -221,7 +221,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
switch (eth->soc->version) {
case 0x7583:
@@ -2182,8 +2186,7 @@ static int airoha_dev_set_features(struc
@@ -2183,8 +2187,7 @@ static int airoha_dev_set_features(struc
{
netdev_features_t diff = netdev->features ^ features;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -231,7 +231,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
struct airoha_eth *eth = qdma->eth;
int qdma_id = qdma - &eth->qdma[0];
int i;
@@ -2225,10 +2228,10 @@ static int airoha_dev_set_features(struc
@@ -2226,10 +2229,10 @@ static int airoha_dev_set_features(struc
if (!p)
continue;
@@ -244,7 +244,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (d->dev == netdev)
continue;
@@ -2245,8 +2248,7 @@ static netdev_tx_t airoha_dev_xmit(struc
@@ -2246,8 +2249,7 @@ static netdev_tx_t airoha_dev_xmit(struc
struct net_device *netdev)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -254,7 +254,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 nr_frags, tag, msg0, msg1, len;
struct airoha_queue_entry *e;
struct netdev_queue *txq;
@@ -2284,7 +2286,7 @@ static netdev_tx_t airoha_dev_xmit(struc
@@ -2285,7 +2287,7 @@ static netdev_tx_t airoha_dev_xmit(struc
}
}
@@ -263,7 +263,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) |
FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f);
@@ -2387,8 +2389,7 @@ static void airoha_ethtool_get_drvinfo(s
@@ -2388,8 +2390,7 @@ static void airoha_ethtool_get_drvinfo(s
struct ethtool_drvinfo *info)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -273,7 +273,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
strscpy(info->driver, eth->dev->driver->name, sizeof(info->driver));
strscpy(info->bus_info, dev_name(eth->dev), sizeof(info->bus_info));
@@ -2401,7 +2402,7 @@ static void airoha_ethtool_get_mac_stats
@@ -2402,7 +2403,7 @@ static void airoha_ethtool_get_mac_stats
struct airoha_gdm_port *port = dev->port;
unsigned int start;
@@ -282,7 +282,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
do {
start = u64_stats_fetch_begin(&port->stats.syncp);
stats->FramesTransmittedOK = port->stats.tx_ok_pkts;
@@ -2441,7 +2442,7 @@ airoha_ethtool_get_rmon_stats(struct net
@@ -2442,7 +2443,7 @@ airoha_ethtool_get_rmon_stats(struct net
ARRAY_SIZE(hw_stats->rx_len) + 1);
*ranges = airoha_ethtool_rmon_ranges;
@@ -291,7 +291,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
do {
int i;
@@ -2461,18 +2462,17 @@ static int airoha_qdma_set_chan_tx_sched
@@ -2462,18 +2463,17 @@ static int airoha_qdma_set_chan_tx_sched
const u16 *weights, u8 n_weights)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -312,7 +312,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
TWRR_RW_CMD_MASK |
FIELD_PREP(TWRR_CHAN_IDX_MASK, channel) |
FIELD_PREP(TWRR_QUEUE_IDX_MASK, i) |
@@ -2480,13 +2480,12 @@ static int airoha_qdma_set_chan_tx_sched
@@ -2481,13 +2481,12 @@ static int airoha_qdma_set_chan_tx_sched
err = read_poll_timeout(airoha_qdma_rr, status,
status & TWRR_RW_CMD_DONE,
USEC_PER_MSEC, 10 * USEC_PER_MSEC,
@@ -328,7 +328,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
CHAN_QOS_MODE_MASK(channel),
__field_prep(CHAN_QOS_MODE_MASK(channel), mode));
@@ -2552,9 +2551,9 @@ static int airoha_qdma_get_tx_ets_stats(
@@ -2553,9 +2552,9 @@ static int airoha_qdma_get_tx_ets_stats(
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
@@ -340,7 +340,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
REG_CNTR_VAL((channel << 1) + 1));
u64 tx_packets = (cpu_tx_packets - port->cpu_tx_packets) +
(fwd_tx_packets - port->fwd_tx_packets);
@@ -2818,17 +2817,16 @@ static int airoha_qdma_set_tx_rate_limit
@@ -2819,17 +2818,16 @@ static int airoha_qdma_set_tx_rate_limit
u32 bucket_size)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -360,7 +360,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
REG_EGRESS_TRTCM_CFG,
i, rate, bucket_size);
if (err)
@@ -2878,11 +2876,11 @@ static int airoha_tc_htb_alloc_leaf_queu
@@ -2879,11 +2877,11 @@ static int airoha_tc_htb_alloc_leaf_queu
return 0;
}
@@ -374,7 +374,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
int i;
for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
@@ -2961,7 +2959,6 @@ static int airoha_dev_tc_matchall(struct
@@ -2962,7 +2960,6 @@ static int airoha_dev_tc_matchall(struct
{
enum trtcm_unit_type unit_type = TRTCM_BYTE_UNIT;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -382,7 +382,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 rate = 0, bucket_size = 0;
switch (f->command) {
@@ -2986,7 +2983,7 @@ static int airoha_dev_tc_matchall(struct
@@ -2987,7 +2984,7 @@ static int airoha_dev_tc_matchall(struct
fallthrough;
}
case TC_CLSMATCHALL_DESTROY:
@@ -391,7 +391,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
unit_type);
default:
return -EOPNOTSUPP;
@@ -2998,8 +2995,7 @@ static int airoha_dev_setup_tc_block_cb(
@@ -2999,8 +2996,7 @@ static int airoha_dev_setup_tc_block_cb(
{
struct net_device *netdev = cb_priv;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -401,7 +401,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (!tc_can_offload(netdev))
return -EOPNOTSUPP;
@@ -3234,7 +3230,7 @@ static void airoha_mac_link_up(struct ph
@@ -3235,7 +3231,7 @@ static void airoha_mac_link_up(struct ph
struct airoha_gdm_dev *dev = container_of(config, struct airoha_gdm_dev,
phylink_config);
struct airoha_gdm_port *port = dev->port;
@@ -37,7 +37,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
val = (addr[0] << 16) | (addr[1] << 8) | addr[2];
airoha_fe_wr(eth, reg, val);
@@ -2037,7 +2035,7 @@ static int airoha_dev_init(struct net_de
@@ -2038,7 +2036,7 @@ static int airoha_dev_init(struct net_de
int i;
/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */
@@ -22,7 +22,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2834,30 +2834,40 @@ static int airoha_qdma_set_tx_rate_limit
@@ -2835,30 +2835,40 @@ static int airoha_qdma_set_tx_rate_limit
return 0;
}
@@ -75,7 +75,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
err = netif_set_real_num_tx_queues(netdev, num_tx_queues + 1);
if (err) {
@@ -2865,13 +2875,17 @@ static int airoha_tc_htb_alloc_leaf_queu
@@ -2866,13 +2876,17 @@ static int airoha_tc_htb_alloc_leaf_queu
opt->quantum);
NL_SET_ERR_MSG_MOD(opt->extack,
"failed setting real_num_tx_queues");
@@ -95,7 +95,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
static int airoha_qdma_set_rx_meter(struct airoha_gdm_dev *dev,
@@ -3052,11 +3066,13 @@ static int airoha_dev_setup_tc_block(str
@@ -3053,11 +3067,13 @@ static int airoha_dev_setup_tc_block(str
static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -111,7 +111,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev,
@@ -3064,9 +3080,8 @@ static int airoha_tc_htb_delete_leaf_que
@@ -3065,9 +3081,8 @@ static int airoha_tc_htb_delete_leaf_que
{
u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -122,7 +122,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
return -EINVAL;
}
@@ -3079,10 +3094,9 @@ static int airoha_tc_htb_delete_leaf_que
@@ -3080,10 +3095,9 @@ static int airoha_tc_htb_delete_leaf_que
static int airoha_tc_htb_destroy(struct net_device *netdev)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -134,7 +134,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_tc_remove_htb_queue(netdev, q);
return 0;
@@ -3093,9 +3107,8 @@ static int airoha_tc_get_htb_get_leaf_qu
@@ -3094,9 +3108,8 @@ static int airoha_tc_get_htb_get_leaf_qu
{
u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -145,7 +145,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
return -EINVAL;
}
@@ -3114,6 +3127,7 @@ static int airoha_tc_setup_qdisc_htb(str
@@ -3115,6 +3128,7 @@ static int airoha_tc_setup_qdisc_htb(str
case TC_HTB_DESTROY:
return airoha_tc_htb_destroy(dev);
case TC_HTB_NODE_MODIFY:
@@ -21,7 +21,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2547,19 +2547,17 @@ static int airoha_qdma_get_tx_ets_stats(
@@ -2548,19 +2548,17 @@ static int airoha_qdma_get_tx_ets_stats(
struct tc_ets_qopt_offload *opt)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -171,7 +171,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
/* PPE module requires untagged packets to work
* properly and it provides DSA port index via the
* DMA descriptor. Report DSA tag to the DSA stack
@@ -996,24 +988,27 @@ static void airoha_qdma_wake_netdev_txqs
@@ -997,24 +989,27 @@ static void airoha_qdma_wake_netdev_txqs
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -209,7 +209,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
}
q->txq_stopped = false;
@@ -1902,11 +1897,9 @@ static int airoha_dev_open(struct net_de
@@ -1903,11 +1898,9 @@ static int airoha_dev_open(struct net_de
GLOBAL_CFG_RX_DMA_EN_MASK);
atomic_inc(&qdma->users);
@@ -223,7 +223,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id),
pse_port);
@@ -2001,7 +1994,7 @@ static int airoha_set_gdm2_loopback(stru
@@ -2002,7 +1995,7 @@ static int airoha_set_gdm2_loopback(stru
airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));
airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX));
@@ -232,7 +232,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (src_port < 0)
return src_port;
@@ -2018,7 +2011,7 @@ static int airoha_set_gdm2_loopback(stru
@@ -2019,7 +2012,7 @@ static int airoha_set_gdm2_loopback(stru
airoha_ppe_set_cpu_port(dev, i, AIROHA_GDM2_IDX);
if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) {
@@ -241,7 +241,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, mask,
__field_prep(mask, AIROHA_GDM2_IDX));
@@ -2032,7 +2025,7 @@ static int airoha_dev_init(struct net_de
@@ -2033,7 +2026,7 @@ static int airoha_dev_init(struct net_de
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
struct airoha_eth *eth = dev->eth;
@@ -250,7 +250,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */
dev->qdma = &eth->qdma[!airoha_is_lan_gdm_dev(dev)];
@@ -2055,8 +2048,8 @@ static int airoha_dev_init(struct net_de
@@ -2056,8 +2049,8 @@ static int airoha_dev_init(struct net_de
break;
}
@@ -261,7 +261,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
return 0;
}
@@ -2221,20 +2214,26 @@ static int airoha_dev_set_features(struc
@@ -2222,20 +2215,26 @@ static int airoha_dev_set_features(struc
} else {
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *p = eth->ports[i];
@@ -296,7 +296,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
airoha_fe_lro_disable(eth, qdma_id);
}
@@ -2285,7 +2284,8 @@ static netdev_tx_t airoha_dev_xmit(struc
@@ -2286,7 +2285,8 @@ static netdev_tx_t airoha_dev_xmit(struc
}
fport = airoha_get_fe_port(dev);
@@ -306,7 +306,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f);
q = &qdma->q_tx[qid];
@@ -3221,12 +3221,15 @@ bool airoha_is_valid_gdm_dev(struct airo
@@ -3222,12 +3222,15 @@ bool airoha_is_valid_gdm_dev(struct airo
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -324,7 +324,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
return false;
@@ -3350,10 +3353,11 @@ static int airoha_setup_phylink(struct n
@@ -3351,10 +3354,11 @@ static int airoha_setup_phylink(struct n
static int airoha_alloc_gdm_device(struct airoha_eth *eth,
struct airoha_gdm_port *port,
@@ -338,7 +338,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
int err;
netdev = devm_alloc_etherdev_mqs(eth->dev, sizeof(*dev),
@@ -3371,7 +3375,6 @@ static int airoha_alloc_gdm_device(struc
@@ -3372,7 +3376,6 @@ static int airoha_alloc_gdm_device(struc
netdev->hw_features = AIROHA_HW_FEATURES | NETIF_F_LRO;
netdev->features |= AIROHA_HW_FEATURES;
netdev->vlan_features = AIROHA_HW_FEATURES;
@@ -346,7 +346,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
SET_NETDEV_DEV(netdev, eth->dev);
/* reserve hw queues for HTB offloading */
@@ -3389,11 +3392,25 @@ static int airoha_alloc_gdm_device(struc
@@ -3390,11 +3393,25 @@ static int airoha_alloc_gdm_device(struc
netdev->dev_addr);
}
@@ -373,7 +373,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
#if defined(CONFIG_PCS_AIROHA)
if (airhoa_is_phy_external(port)) {
@@ -3411,7 +3428,8 @@ static int airoha_alloc_gdm_port(struct
@@ -3412,7 +3429,8 @@ static int airoha_alloc_gdm_port(struct
{
const __be32 *id_ptr = of_get_property(np, "reg", NULL);
struct airoha_gdm_port *port;
@@ -383,7 +383,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 id;
if (!id_ptr) {
@@ -3439,15 +3457,51 @@ static int airoha_alloc_gdm_port(struct
@@ -3440,15 +3458,51 @@ static int airoha_alloc_gdm_port(struct
u64_stats_init(&port->stats.syncp);
spin_lock_init(&port->stats.lock);
port->id = id;
@@ -438,7 +438,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
static int airoha_register_gdm_devices(struct airoha_eth *eth)
@@ -3456,14 +3510,22 @@ static int airoha_register_gdm_devices(s
@@ -3457,14 +3511,22 @@ static int airoha_register_gdm_devices(s
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -465,7 +465,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
set_bit(DEV_STATE_REGISTERED, &eth->state);
@@ -3570,18 +3632,27 @@ error_napi_stop:
@@ -3571,18 +3633,27 @@ error_napi_stop:
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -499,7 +499,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
airoha_metadata_dst_free(port);
}
@@ -3603,19 +3674,26 @@ static void airoha_remove(struct platfor
@@ -3604,19 +3675,26 @@ static void airoha_remove(struct platfor
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -531,7 +531,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_metadata_dst_free(port);
}
airoha_hw_cleanup(eth);
@@ -3677,6 +3755,39 @@ static u32 airoha_en7581_get_vip_port(st
@@ -3678,6 +3756,39 @@ static u32 airoha_en7581_get_vip_port(st
return 0;
}
@@ -571,7 +571,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static const char * const an7583_xsi_rsts_names[] = {
"hsi0-mac",
"hsi1-mac",
@@ -3725,6 +3836,36 @@ static u32 airoha_an7583_get_vip_port(st
@@ -3726,6 +3837,36 @@ static u32 airoha_an7583_get_vip_port(st
return 0;
}
@@ -608,7 +608,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static const struct airoha_eth_soc_data en7581_soc_data = {
.version = 0x7581,
.xsi_rsts_names = en7581_xsi_rsts_names,
@@ -3733,6 +3874,7 @@ static const struct airoha_eth_soc_data
@@ -3734,6 +3875,7 @@ static const struct airoha_eth_soc_data
.ops = {
.get_sport = airoha_en7581_get_sport,
.get_vip_port = airoha_en7581_get_vip_port,
@@ -616,7 +616,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
},
};
@@ -3744,6 +3886,7 @@ static const struct airoha_eth_soc_data
@@ -3745,6 +3887,7 @@ static const struct airoha_eth_soc_data
.ops = {
.get_sport = airoha_an7583_get_sport,
.get_vip_port = airoha_an7583_get_vip_port,
@@ -682,7 +682,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_fe_rmw(eth, REG_PPE_MTU(i, p),
FP0_EGRESS_MTU_MASK |
FP1_EGRESS_MTU_MASK,
@@ -178,11 +176,24 @@ static void airoha_ppe_hw_init(struct ai
@@ -178,11 +176,27 @@ static void airoha_ppe_hw_init(struct ai
AIROHA_MAX_MTU) |
FIELD_PREP(FP1_EGRESS_MTU_MASK,
AIROHA_MAX_MTU));
@@ -698,6 +698,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+
+ for (j = 0; j < ARRAY_SIZE(port->devs); j++) {
+ struct airoha_gdm_dev *dev = port->devs[j];
+ int ppe_id;
+ u8 fport;
+
+ if (!dev)
@@ -705,8 +706,10 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
- airoha_ppe_set_cpu_port(port->dev, i,
- airoha_get_fe_port(port->dev));
+ ppe_id = !airoha_is_lan_gdm_dev(dev) &&
+ airoha_ppe_is_enabled(eth, 1);
+ fport = airoha_get_fe_port(dev);
+ airoha_ppe_set_cpu_port(dev, i, fport);
+ airoha_ppe_set_cpu_port(dev, ppe_id, fport);
}
}
}
@@ -23,7 +23,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1858,8 +1858,8 @@ static int airoha_dev_open(struct net_de
@@ -1859,8 +1859,8 @@ static int airoha_dev_open(struct net_de
int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
@@ -33,7 +33,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
#if defined(CONFIG_PCS_AIROHA)
if (airhoa_is_phy_external(port)) {
@@ -1887,10 +1887,20 @@ static int airoha_dev_open(struct net_de
@@ -1888,10 +1888,20 @@ static int airoha_dev_open(struct net_de
airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
@@ -58,7 +58,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG,
GLOBAL_CFG_TX_DMA_EN_MASK |
@@ -1906,6 +1916,30 @@ static int airoha_dev_open(struct net_de
@@ -1907,6 +1917,30 @@ static int airoha_dev_open(struct net_de
return 0;
}
@@ -89,7 +89,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static int airoha_dev_stop(struct net_device *netdev)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -1918,8 +1952,12 @@ static int airoha_dev_stop(struct net_de
@@ -1919,8 +1953,12 @@ static int airoha_dev_stop(struct net_de
for (i = 0; i < netdev->num_tx_queues; i++)
netdev_tx_reset_subqueue(netdev, i);
@@ -104,7 +104,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (atomic_dec_and_test(&qdma->users)) {
airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
@@ -2081,13 +2119,10 @@ static int airoha_dev_change_mtu(struct
@@ -2082,13 +2120,10 @@ static int airoha_dev_change_mtu(struct
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
@@ -29,7 +29,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2058,36 +2058,80 @@ static int airoha_set_gdm2_loopback(stru
@@ -2059,36 +2059,80 @@ static int airoha_set_gdm2_loopback(stru
return 0;
}
@@ -163,7 +163,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static inline bool airoha_is_7581(struct airoha_eth *eth)
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -351,7 +351,7 @@ static int airoha_ppe_foe_entry_prepare(
@@ -354,7 +354,7 @@ static int airoha_ppe_foe_entry_prepare(
return -EINVAL;
port = dev->port;
@@ -111,7 +111,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr,
@@ -1985,13 +2039,18 @@ static int airoha_dev_stop(struct net_de
@@ -1986,13 +2040,18 @@ static int airoha_dev_stop(struct net_de
static int airoha_dev_set_macaddr(struct net_device *netdev, void *p)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -145,7 +145,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
u32 hash);
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -1494,12 +1494,10 @@ void airoha_ppe_check_skb(struct airoha_
@@ -1497,12 +1497,10 @@ void airoha_ppe_check_skb(struct airoha_
airoha_ppe_foe_insert_entry(ppe, skb, hash, rx_wlan);
}
@@ -17,7 +17,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2055,7 +2055,7 @@ static int airoha_dev_set_macaddr(struct
@@ -2056,7 +2056,7 @@ static int airoha_dev_set_macaddr(struct
return 0;
}
@@ -26,7 +26,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
{
struct airoha_gdm_port *port = dev->port;
struct airoha_eth *eth = dev->eth;
@@ -2187,7 +2187,7 @@ static int airoha_dev_init(struct net_de
@@ -2188,7 +2188,7 @@ static int airoha_dev_init(struct net_de
(port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)) {
int err;
@@ -19,7 +19,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1915,6 +1915,11 @@ static int airoha_dev_open(struct net_de
@@ -1916,6 +1916,11 @@ static int airoha_dev_open(struct net_de
u32 cur_len, pse_port = FE_PSE_PORT_PPE1;
struct airoha_qdma *qdma = dev->qdma;
@@ -31,7 +31,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
#if defined(CONFIG_PCS_AIROHA)
if (airhoa_is_phy_external(port)) {
err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0);
@@ -2117,6 +2122,45 @@ static int airoha_enable_gdm2_loopback(s
@@ -2118,6 +2123,45 @@ static int airoha_enable_gdm2_loopback(s
return 0;
}
@@ -77,7 +77,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static struct airoha_gdm_dev *
airoha_get_wan_gdm_dev(struct airoha_eth *eth)
{
@@ -2521,6 +2565,80 @@ error:
@@ -2522,6 +2566,80 @@ error:
return NETDEV_TX_OK;
}
@@ -158,7 +158,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static void airoha_ethtool_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
@@ -2529,6 +2647,7 @@ static void airoha_ethtool_get_drvinfo(s
@@ -2530,6 +2648,7 @@ static void airoha_ethtool_get_drvinfo(s
strscpy(info->driver, eth->dev->driver->name, sizeof(info->driver));
strscpy(info->bus_info, dev_name(eth->dev), sizeof(info->bus_info));
@@ -166,7 +166,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
static void airoha_ethtool_get_mac_stats(struct net_device *netdev,
@@ -2593,6 +2712,56 @@ airoha_ethtool_get_rmon_stats(struct net
@@ -2594,6 +2713,56 @@ airoha_ethtool_get_rmon_stats(struct net
} while (u64_stats_fetch_retry(&port->stats.syncp, start));
}
@@ -223,7 +223,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,
int channel, enum tx_sched_mode mode,
const u16 *weights, u8 n_weights)
@@ -3314,6 +3483,10 @@ static const struct ethtool_ops airoha_e
@@ -3315,6 +3484,10 @@ static const struct ethtool_ops airoha_e
.get_rmon_stats = airoha_ethtool_get_rmon_stats,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.get_link = ethtool_op_get_link,
@@ -28,37 +28,24 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+ airoha_fe_rmw(eth, REG_GDM_LEN_CFG(p),
+ GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
+ FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
+ FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU));
+ FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_RX_SIZE));
+ }
airoha_fe_rmw(eth, REG_CDM_VLAN_CTRL(1), CDM_VLAN_MASK,
FIELD_PREP(CDM_VLAN_MASK, 0x8100));
@@ -1907,13 +1912,37 @@ static void airoha_update_hw_stats(struc
@@ -1908,13 +1913,24 @@ static void airoha_update_hw_stats(struc
spin_unlock(&port->stats.lock);
}
+void airoha_set_port_mtu(struct airoha_eth *eth, struct airoha_gdm_port *port)
+static void airoha_dev_set_mtu(struct net_device *netdev)
+{
+ u32 mtu = 0, index;
+ int i;
+ struct airoha_gdm_dev *dev = netdev_priv(netdev);
+
+ for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
+ struct airoha_gdm_dev *dev = port->devs[i];
+ struct net_device *netdev;
+
+ if (!dev)
+ continue;
+
+ netdev = dev->dev;
+ if (netif_running(netdev))
+ mtu = max_t(u32, mtu, netdev->mtu);
+ }
+
+ index = port->id == AIROHA_GDM4_IDX ? 7 : port->id;
+ for (i = 0; i < eth->soc->num_ppe; i++)
+ airoha_fe_rmw(eth, REG_PPE_MTU(i, index),
+ FP_EGRESS_MTU_MASK(index),
+ __field_prep(FP_EGRESS_MTU_MASK(index), mtu));
+ airoha_ppe_set_mtu(dev);
+ if (!airoha_is_lan_gdm_dev(dev))
+ airoha_fe_rmw(dev->eth, REG_WAN_MTU0,
+ WAN_MTU0_MASK,
+ FIELD_PREP(WAN_MTU0_MASK, netdev->mtu));
+}
+
static int airoha_dev_open(struct net_device *netdev)
@@ -73,7 +60,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
if (port->id == AIROHA_GDM2_IDX && airoha_is_lan_gdm_dev(dev)) {
/* GDM2 can be used just as wan */
@@ -1946,19 +1975,12 @@ static int airoha_dev_open(struct net_de
@@ -1947,19 +1963,7 @@ static int airoha_dev_open(struct net_de
airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
@@ -90,16 +77,11 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
- FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
- FIELD_PREP(GDM_LONG_LEN_MASK, len));
- }
+ airoha_set_port_mtu(qdma->eth, port);
+ if (!airoha_is_lan_gdm_dev(dev))
+ airoha_fe_rmw(qdma->eth, REG_WAN_MTU0,
+ WAN_MTU0_MASK,
+ FIELD_PREP(WAN_MTU0_MASK, netdev->mtu));
+
+ airoha_dev_set_mtu(netdev);
port->users++;
airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG,
@@ -1975,30 +1997,6 @@ static int airoha_dev_open(struct net_de
@@ -1976,30 +1980,6 @@ static int airoha_dev_open(struct net_de
return 0;
}
@@ -130,7 +112,16 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
static int airoha_dev_stop(struct net_device *netdev)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -2082,10 +2080,6 @@ static int airoha_enable_gdm2_loopback(s
@@ -2013,7 +1993,7 @@ static int airoha_dev_stop(struct net_de
netdev_tx_reset_subqueue(netdev, i);
if (--port->users)
- airoha_set_port_mtu(dev->eth, port);
+ airoha_ppe_set_mtu(dev);
else
airoha_set_gdm_port_fwd_cfg(qdma->eth,
REG_GDM_FWD_CFG(port->id),
@@ -2083,10 +2063,6 @@ static int airoha_enable_gdm2_loopback(s
FIELD_PREP(LPBK_CHAN_MASK, chan) |
LBK_GAP_MODE_MASK | LBK_LEN_MODE_MASK |
LBK_CHAN_MODE_MASK | LPBK_EN_MASK);
@@ -141,29 +132,80 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
/* Forward the traffic to the proper GDM port */
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
: FE_PSE_PORT_GDM4;
@@ -2612,6 +2606,9 @@ static int airoha_dev_set_wan_flag(struc
@@ -2270,7 +2246,7 @@ static int airoha_dev_change_mtu(struct
WRITE_ONCE(netdev->mtu, mtu);
if (port->users)
- airoha_set_port_mtu(dev->eth, port);
+ airoha_dev_set_mtu(netdev);
return 0;
}
@@ -2613,6 +2589,7 @@ static int airoha_dev_set_wan_flag(struc
default:
return -EOPNOTSUPP;
}
+ airoha_fe_rmw(eth, REG_WAN_MTU0,
+ WAN_MTU0_MASK,
+ FIELD_PREP(WAN_MTU0_MASK, netdev->mtu));
+ airoha_dev_set_mtu(netdev);
} else {
switch (port->id) {
case AIROHA_GDM3_IDX:
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -706,6 +706,7 @@ int airoha_get_fe_port(struct airoha_gdm
@@ -23,6 +23,7 @@
#define AIROHA_MAX_DSA_PORTS 7
#define AIROHA_MAX_NUM_RSTS 3
#define AIROHA_MAX_MTU 9220
+#define AIROHA_MAX_RX_SIZE 16128
#define AIROHA_MAX_PACKET_SIZE 2048
#define AIROHA_NUM_QOS_CHANNELS 4
#define AIROHA_NUM_QOS_QUEUES 8
@@ -706,6 +707,7 @@ int airoha_get_fe_port(struct airoha_gdm
bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
struct airoha_gdm_dev *dev);
+void airoha_set_port_mtu(struct airoha_eth *eth, struct airoha_gdm_port *port);
+void airoha_ppe_set_mtu(struct airoha_gdm_dev *dev);
void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport);
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -116,8 +116,6 @@ static void airoha_ppe_hw_init(struct ai
@@ -98,6 +98,35 @@ void airoha_ppe_set_cpu_port(struct airo
__field_prep(DFT_CPORT_MASK(fport), fe_cpu_port));
}
+void airoha_ppe_set_mtu(struct airoha_gdm_dev *dev)
+{
+ struct airoha_gdm_port *port = dev->port;
+ struct airoha_eth *eth = dev->eth;
+ int i, ppe_id, index;
+ u32 mtu = 0;
+
+ for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
+ struct airoha_gdm_dev *d = port->devs[i];
+ struct net_device *netdev;
+
+ if (!d)
+ continue;
+
+ if (d->qdma != dev->qdma)
+ continue;
+
+ netdev = d->dev;
+ if (netif_running(netdev))
+ mtu = max_t(u32, mtu, netdev->mtu);
+ }
+
+ ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1);
+ index = port->id == AIROHA_GDM4_IDX ? 7 : port->id;
+ airoha_fe_rmw(eth, REG_PPE_MTU(ppe_id, index),
+ FP_EGRESS_MTU_MASK(index),
+ __field_prep(FP_EGRESS_MTU_MASK(index), mtu));
+}
+
static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
{
u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries;
@@ -116,8 +145,6 @@ static void airoha_ppe_hw_init(struct ai
PPE_RAM_NUM_ENTRIES_SHIFT(sram_ppe_num_data_entries);
for (i = 0; i < eth->soc->num_ppe; i++) {
@@ -172,7 +214,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
airoha_fe_wr(eth, REG_PPE_TB_BASE(i),
ppe->foe_dma + sram_tb_size);
@@ -167,15 +165,6 @@ static void airoha_ppe_hw_init(struct ai
@@ -167,15 +194,6 @@ static void airoha_ppe_hw_init(struct ai
airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED);
airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i),
PPE_FLOW_CFG_IP6_6RD_MASK);
@@ -188,14 +230,14 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
}
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
@@ -185,6 +174,7 @@ static void airoha_ppe_hw_init(struct ai
if (!port)
continue;
+ airoha_set_port_mtu(eth, port);
for (j = 0; j < ARRAY_SIZE(port->devs); j++) {
struct airoha_gdm_dev *dev = port->devs[j];
u8 fport;
@@ -197,6 +215,7 @@ static void airoha_ppe_hw_init(struct ai
airoha_ppe_is_enabled(eth, 1);
fport = airoha_get_fe_port(dev);
airoha_ppe_set_cpu_port(dev, ppe_id, fport);
+ airoha_ppe_set_mtu(dev);
}
}
}
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -341,9 +341,8 @@
@@ -46,7 +46,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
airoha_fe_crsn_qsel_init(eth);
airoha_fe_clear(eth, REG_FE_CPORT_CFG, FE_CPORT_QUEUE_XFC_MASK);
@@ -1767,149 +1775,169 @@ static void airoha_qdma_stop_napi(struct
@@ -1768,149 +1776,169 @@ static void airoha_qdma_stop_napi(struct
}
}
@@ -245,9 +245,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+
+ u64_stats_update_end(&dev->stats.syncp);
+}
- /* reset mib counters */
- airoha_fe_set(eth, REG_FE_GDM_MIB_CLEAR(port->id),
+
+static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
+{
+ struct airoha_gdm_port *port = dev->port;
@@ -259,7 +257,9 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+ if (port->devs[i])
+ airoha_dev_get_hw_stats(port->devs[i]);
+ }
+
- /* reset mib counters */
- airoha_fe_set(eth, REG_FE_GDM_MIB_CLEAR(port->id),
+ /* Reset MIB counters */
+ airoha_fe_set(dev->eth, REG_FE_GDM_MIB_CLEAR(port->id),
FE_GDM_MIB_RX_CLEAR_MASK | FE_GDM_MIB_TX_CLEAR_MASK);
@@ -269,8 +269,8 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+ spin_unlock(&port->stats_lock);
}
void airoha_set_port_mtu(struct airoha_eth *eth, struct airoha_gdm_port *port)
@@ -2237,23 +2265,22 @@ static void airoha_dev_get_stats64(struc
static void airoha_dev_set_mtu(struct net_device *netdev)
@@ -2220,23 +2248,22 @@ static void airoha_dev_get_stats64(struc
struct rtnl_link_stats64 *storage)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -306,7 +306,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
}
static int airoha_dev_change_mtu(struct net_device *netdev, int mtu)
@@ -2651,20 +2678,19 @@ static void airoha_ethtool_get_mac_stats
@@ -2632,20 +2659,19 @@ static void airoha_ethtool_get_mac_stats
struct ethtool_eth_mac_stats *stats)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -336,7 +336,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
}
static const struct ethtool_rmon_hist_range airoha_ethtool_rmon_ranges[] = {
@@ -2684,8 +2710,7 @@ airoha_ethtool_get_rmon_stats(struct net
@@ -2665,8 +2691,7 @@ airoha_ethtool_get_rmon_stats(struct net
const struct ethtool_rmon_hist_range **ranges)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -346,7 +346,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
unsigned int start;
BUILD_BUG_ON(ARRAY_SIZE(airoha_ethtool_rmon_ranges) !=
@@ -2698,7 +2723,7 @@ airoha_ethtool_get_rmon_stats(struct net
@@ -2679,7 +2704,7 @@ airoha_ethtool_get_rmon_stats(struct net
do {
int i;
@@ -355,7 +355,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
stats->fragments = hw_stats->rx_fragment;
stats->jabbers = hw_stats->rx_jabber;
for (i = 0; i < ARRAY_SIZE(airoha_ethtool_rmon_ranges) - 1;
@@ -2706,7 +2731,7 @@ airoha_ethtool_get_rmon_stats(struct net
@@ -2687,7 +2712,7 @@ airoha_ethtool_get_rmon_stats(struct net
stats->hist[i] = hw_stats->rx_len[i];
stats->hist_tx[i] = hw_stats->tx_len[i];
}
@@ -364,7 +364,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
}
static int airoha_ethtool_set_priv_flags(struct net_device *netdev, u32 flags)
@@ -3714,6 +3739,7 @@ static int airoha_alloc_gdm_device(struc
@@ -3695,6 +3720,7 @@ static int airoha_alloc_gdm_device(struc
netdev->dev.of_node = of_node_get(np);
dev = netdev_priv(netdev);
@@ -372,7 +372,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
dev->dev = netdev;
dev->port = port;
dev->eth = eth;
@@ -3762,9 +3788,8 @@ static int airoha_alloc_gdm_port(struct
@@ -3743,9 +3769,8 @@ static int airoha_alloc_gdm_port(struct
if (!port)
return -ENOMEM;
@@ -385,7 +385,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
err = airoha_metadata_dst_alloc(port);
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -227,8 +227,6 @@ struct airoha_tx_irq_queue {
@@ -228,8 +228,6 @@ struct airoha_tx_irq_queue {
};
struct airoha_hw_stats {
@@ -394,7 +394,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
struct u64_stats_sync syncp;
/* get_stats64 */
@@ -572,6 +570,8 @@ struct airoha_gdm_dev {
@@ -573,6 +571,8 @@ struct airoha_gdm_dev {
u32 flags;
int nbq;
@@ -403,7 +403,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
};
struct airoha_gdm_port {
@@ -579,7 +579,8 @@ struct airoha_gdm_port {
@@ -580,7 +580,8 @@ struct airoha_gdm_port {
int id;
int users;
@@ -18,7 +18,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2362,17 +2362,9 @@ static u32 airoha_get_dsa_tag(struct sk_
@@ -2345,17 +2345,9 @@ static u32 airoha_get_dsa_tag(struct sk_
int airoha_get_fe_port(struct airoha_gdm_dev *dev)
{
struct airoha_gdm_port *port = dev->port;
+198
View File
@@ -0,0 +1,198 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "ar9344.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h>
/ {
compatible = "meraki,z1", "qca,ar9344";
model = "Cisco Meraki Z1";
aliases {
led-boot = &led_power_orange;
led-failsafe = &led_power_orange;
led-upgrade = &led_power_orange;
label-mac-device = &eth0;
};
chosen {
bootargs = "console=ttyS0,115200n8";
};
keys {
compatible = "gpio-keys";
reset {
label = "Reset button";
linux,code = <KEY_RESTART>;
gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
debounce-interval = <60>;
};
};
leds {
compatible = "gpio-leds";
led_power_orange: led-0 {
function = LED_FUNCTION_POWER;
color = <LED_COLOR_ID_ORANGE>;
gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
default-state = "on";
panic-indicator;
};
};
};
&ref {
clock-frequency = <40000000>;
};
&gpio {
pinctrl-names = "default";
pinctrl-0 = <&jtag_disable_pins>;
gpio_ext_lna0 {
gpio-hog;
gpios = <18 GPIO_ACTIVE_HIGH>;
output-low;
line-name = "z1:ext:lna0";
};
gpio_ext_lna1 {
gpio-hog;
gpios = <19 GPIO_ACTIVE_HIGH>;
output-low;
line-name = "z1:ext:lna1";
};
};
&usb {
status = "okay";
};
&usb_phy {
status = "okay";
};
&pcie {
status = "okay";
ath9k: wifi@0,0 {
compatible = "pci168c,002a";
reg = <0x0000 0 0 0 0>;
qca,no-eeprom;
nvmem-cells = <&macaddr_board_66 3>;
nvmem-cell-names = "mac-address";
};
};
&wmac {
status = "okay";
qca,no-eeprom;
nvmem-cells = <&macaddr_board_66 2>;
nvmem-cell-names = "mac-address";
};
&nand {
status = "okay";
nand-ecc-mode = "soft";
nand-ecc-algo = "bch";
nand-ecc-strength = <4>;
nand-ecc-step-size = <512>;
nand-is-boot-medium;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "loader1";
reg = <0x0 0x20000>;
read-only;
};
partition@20000 {
label = "kernel";
reg = <0x20000 0x7e0000>;
};
partition@800000 {
label = "loader2";
reg = <0x800000 0x20000>;
read-only;
};
partition@820000 {
label = "recovery";
reg = <0x820000 0x7e0000>;
};
partition@1000000 {
label = "ubi";
reg = <0x1000000 0x6fe0000>;
volumes {
ubi-volume-board-config {
volname = "board-config";
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_board_66: macaddr@66 {
compatible = "mac-base";
reg = <0x66 0x6>;
#nvmem-cell-cells = <1>;
};
};
};
};
};
partition@7fe0000 {
label = "origcaldata";
reg = <0x7fe0000 0x20000>;
read-only;
};
};
};
&mdio0 {
status = "okay";
phy0: ethernet-phy@0 {
reg = <0>;
phy-mode = "rgmii";
qca,ar8327-initvals = <
0x04 0x07600000 /* PORT0 PAD MODE CTRL */
0x7c 0x0000007e /* PORT0_STATUS */
>;
};
};
&eth0 {
status = "okay";
pll-data = <0x06000000 0x00000101 0x00001313>;
phy-mode = "rgmii-id";
nvmem-cells = <&macaddr_board_66 0>;
nvmem-cell-names = "mac-address";
fixed-link {
speed = <1000>;
full-duplex;
};
gmac-config {
device = <&gmac>;
rgmii-gmac0 = <1>;
switch-only-mode = <1>;
};
};
+27
View File
@@ -19,6 +19,14 @@ define Build/meraki-header
@mv $@.new $@
endef
define Build/meraki-old-nand
-$(STAGING_DIR_HOST)/bin/mkmerakifw-old \
-B $(1) -s \
-i $@ \
-o $@.new
@mv $@.new $@
endef
# attention: only zlib compression is allowed for the boot fs
define Build/zyxel-buildkerneljffs
mkdir -p $@.tmp/boot
@@ -322,6 +330,25 @@ define Device/meraki_mr18
endef
TARGET_DEVICES += meraki_mr18
define Device/meraki_z1
SOC = ar9344
DEVICE_VENDOR := Meraki
DEVICE_MODEL := Z1
DEVICE_PACKAGES := kmod-usb2 kmod-usb-ledtrig-usbport kmod-owl-loader \
kmod-leds-uleds kmod-spi-gpio nu801 -uboot-envtools
KERNEL_SIZE := 8064k
BLOCKSIZE := 128k
PAGESIZE := 2048
LOADER_TYPE := bin
LZMA_TEXT_START := 0x82800000
KERNEL := kernel-bin | append-dtb | lzma | loader-kernel | \
pad-to $$(BLOCKSIZE) | meraki-old-nand z1
KERNEL_INITRAMFS := $$(KERNEL)
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
SUPPORTED_DEVICES += z1
endef
TARGET_DEVICES += meraki_z1
# fake rootfs is mandatory, pad-offset 129 equals (2 * uimage_header + '\0')
define Device/netgear_ath79_nand
DEVICE_VENDOR := NETGEAR
@@ -30,6 +30,9 @@ netgear,pgzng1)
netgear,r6100)
ucidef_set_led_netdev "wan-green" "WAN (green)" "green:wan" "eth1"
;;
meraki,z1)
ucidef_set_led_default "diag" "DIAG" "green:tricolor" "1"
;;
netgear,wndr3700-v4|\
netgear,wndr4300|\
netgear,wndr4300sw|\
@@ -44,6 +44,10 @@ ath79_setup_interfaces()
ucidef_add_switch "switch0" \
"6u@eth1" "1:lan" "2:lan" "3:lan" "4:lan" "5:wan" "0u@eth0"
;;
meraki,z1)
ucidef_add_switch "switch0" \
"0@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "5:wan"
;;
netgear,pgzng1)
ucidef_set_interfaces_lan_wan "eth1" "eth0"
;;
@@ -104,6 +108,10 @@ ath79_setup_macs()
wan_mac=$(mtd_get_mac_binary art 0x0)
lan_mac=$(macaddr_add "$wan_mac" 1)
;;
meraki,z1)
base_mac=$(mtd_get_mac_binary_ubi board-config 102)
wan_mac=$(macaddr_add "$base_mac" 1)
;;
netgear,wndr3700-v4|\
netgear,wndr4300|\
netgear,wndr4300sw|\
@@ -18,6 +18,16 @@ case "$FIRMWARE" in
caldata_extract "odm-caldata" 0x1000 0x440
fi
;;
meraki,z1)
. /lib/upgrade/nand.sh
if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
caldata_extract_ubi "caldata" 0x1000 0x800
else
caldata_extract "origcaldata" 0x1000 0x800
ath9k_patch_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) 2)
fi
;;
*)
caldata_die "board $board is not supported yet"
;;
@@ -34,6 +44,16 @@ case "$FIRMWARE" in
caldata_extract "odm-caldata" 0x5000 0x440
fi
;;
meraki,z1)
. /lib/upgrade/nand.sh
if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
caldata_extract_ubi "caldata" 0x15000 0x1000
else
caldata_extract "origcaldata" 0x15000 0x1000
ath9k_patch_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) 3)
fi
;;
*)
caldata_die "board $board is not supported yet"
;;
@@ -4,6 +4,9 @@
board=$(board_name)
case "$board" in
meraki,z1)
migrate_leds ":tricolor0=:tricolor"
;;
esac
remove_devicename_leds
@@ -1,4 +1,4 @@
From 60a23e663e0c607ae4ed871aaa24d257051ad557 Mon Sep 17 00:00:00 2001
From 1ad83956d550a252fffc473a191dbe155c4a383e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 17:56:35 +0000
Subject: [PATCH 01/19] net: dsa: mxl862xx: store firmware version for feature
@@ -8,15 +8,15 @@ Query the firmware version at init (already done in wait_ready),
cache it in priv->fw_version, and provide MXL862XX_FW_VER_MIN()
for version-gated code paths throughout the driver.
The union mxl862xx_fw_version lays out major/minor/revision so
that the u32 raw field compares with natural version ordering on
both big- and little-endian machines.
MXL862XX_FW_VER() packs major/minor/revision into a u32 with
bitwise shifts so that versions compare with natural ordering,
independent of host endianness.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx.c | 3 +++
drivers/net/dsa/mxl862xx/mxl862xx.h | 36 +++++++++++++++++++++++++++++
2 files changed, 39 insertions(+)
drivers/net/dsa/mxl862xx/mxl862xx.h | 23 +++++++++++++++++++++++
2 files changed, 26 insertions(+)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -40,46 +40,33 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#include <linux/mdio.h>
#include <linux/workqueue.h>
#include <net/dsa.h>
@@ -241,6 +242,38 @@ struct mxl862xx_port {
@@ -241,6 +242,25 @@ struct mxl862xx_port {
spinlock_t stats_lock; /* protects stats accumulators */
};
+/**
+ * union mxl862xx_fw_version - firmware version for comparison and display
+ * struct mxl862xx_fw_version - firmware version for comparison and display
+ * @major: firmware major version
+ * @minor: firmware minor version
+ * @revision: firmware revision number
+ * @raw: combined u32 for direct >= comparison (major most significant)
+ *
+ * The struct layout places major in the most-significant byte of the
+ * u32 on both big- and little-endian machines, so raw values compare
+ * with the natural major > minor > revision ordering.
+ */
+union mxl862xx_fw_version {
+ struct {
+#if defined(__BIG_ENDIAN)
+ u8 major;
+ u8 minor;
+ u16 revision;
+#elif defined(__LITTLE_ENDIAN)
+ u16 revision;
+ u8 minor;
+ u8 major;
+#endif
+ };
+ u32 raw;
+struct mxl862xx_fw_version {
+ u8 major;
+ u8 minor;
+ u16 revision;
+};
+
+#define MXL862XX_FW_VER(maj, min, rev) \
+ ((union mxl862xx_fw_version){ .major = (maj), .minor = (min), \
+ .revision = (rev) }).raw
+ (((u32)(maj) << 24) | ((u32)(min) << 16) | (rev))
+#define MXL862XX_FW_VER_MIN(priv, maj, min, rev) \
+ ((priv)->fw_version.raw >= MXL862XX_FW_VER(maj, min, rev))
+ (MXL862XX_FW_VER((priv)->fw_version.major, (priv)->fw_version.minor, \
+ (priv)->fw_version.revision) >= \
+ MXL862XX_FW_VER(maj, min, rev))
+
/* Bit indices for struct mxl862xx_priv::flags */
#define MXL862XX_FLAG_CRC_ERR 0
#define MXL862XX_FLAG_WORK_STOPPED 1
@@ -258,6 +291,8 @@ struct mxl862xx_port {
@@ -258,6 +278,8 @@ struct mxl862xx_port {
* @drop_meter: index of the single shared zero-rate firmware meter
* used to unconditionally drop traffic (used to block
* flooding)
@@ -88,11 +75,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @ports: per-port state, indexed by switch port number
* @bridges: maps DSA bridge number to firmware bridge ID;
* zero means no firmware bridge allocated for that
@@ -275,6 +310,7 @@ struct mxl862xx_priv {
@@ -275,6 +297,7 @@ struct mxl862xx_priv {
struct work_struct crc_err_work;
unsigned long flags;
u16 drop_meter;
+ union mxl862xx_fw_version fw_version;
+ struct mxl862xx_fw_version fw_version;
struct mxl862xx_port ports[MXL862XX_MAX_PORTS];
u16 bridges[MXL862XX_MAX_BRIDGES + 1];
u16 evlan_ingress_size;
@@ -1,4 +1,4 @@
From cefa0447dc95a4ddd5093f7b8cf35e654870283f Mon Sep 17 00:00:00 2001
From eaf472bfc89692cd3cc5e0298c90791f4c1c3244 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 25 Mar 2026 21:39:30 +0000
Subject: [PATCH 02/19] net: dsa: mxl862xx: move phylink stubs to
@@ -1,4 +1,4 @@
From 3c1d77006daca1df20d612850535bc6050e266ee Mon Sep 17 00:00:00 2001
From 483be884b2fdee28ac70458067c45a1369939144 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 26 Mar 2026 01:50:00 +0000
Subject: [PATCH 03/19] net: dsa: mxl862xx: move API macros to mxl862xx-host.h
@@ -1,32 +1,54 @@
From 3659914c43a587a1ca6418867834831aa518ac35 Mon Sep 17 00:00:00 2001
From 74044a2d2e62fcc3ee2b6cf22742fa94609c529e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:14:33 +0000
Subject: [PATCH 05/19] net: dsa: mxl862xx: add SerDes ethtool statistics
Expose SerDes equalization and signal detect parameters as ethtool
statistics on ports 9-16 (XPCS-backed ports). Uses the XPCS EQ_GET
and SIGNAL_DETECT firmware commands to read TX/RX equalization
coefficients, DFE taps, and link-level signal status.
Expose SerDes equalization parameters as ethtool statistics on
ports 9-16 (XPCS-backed ports). Uses the XPCS EQ_GET firmware
command to read TX/RX equalization coefficients and DFE taps.
The 19 additional stats (serdes_tx_*, serdes_rx_*, serdes_pma_link,
serdes_link_fault, serdes_in_reset) are appended after the standard
RMON counters and gated on firmware >= 1.0.80.
The 15 additional stats (serdes_tx_*, serdes_rx_*) are appended
after the standard RMON counters and gated on firmware >= 1.0.84.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 88 +++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 93 +++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 92 +++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 97 +++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 6 +-
5 files changed, 191 insertions(+), 1 deletion(-)
5 files changed, 198 insertions(+), 1 deletion(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -1812,4 +1812,92 @@ struct mxl862xx_xpcs_reset_cfg {
@@ -1668,4 +1668,96 @@ struct mxl862xx_xpcs_pcs_link_up {
__le16 result;
} __packed;
+/**
+ * struct mxl862xx_xpcs_loopback_cfg - loopback control
+ * @port_id: XPCS port index
+ * @mode: loopback mode. See &enum mxl862xx_xpcs_loopback_mode
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_loopback_cfg {
+ u8 port_id;
+ u8 mode; /* enum mxl862xx_xpcs_loopback_mode */
+ __le16 result;
+} __packed;
+
+/**
+ * struct mxl862xx_xpcs_reset_cfg - XPCS reset
+ * @port_id: XPCS port index
+ * @reset_type: reset type. See &enum mxl862xx_xpcs_reset_type
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_reset_cfg {
+ u8 port_id;
+ u8 reset_type; /* enum mxl862xx_xpcs_reset_type */
+ __le16 result;
+} __packed;
+
+/**
+ * struct mxl862xx_xpcs_eq_item - single equalization parameter
+ * @value: current initial value
@@ -94,42 +116,21 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ struct mxl862xx_xpcs_tx_eq_info tx;
+ struct mxl862xx_xpcs_rx_eq_info rx;
+} __packed;
+
+/**
+ * struct mxl862xx_xpcs_signal_detect - signal detect status
+ * @port_id: XPCS port index (0 or 1)
+ * @rx_signal: RX signal detected
+ * @pma_link: PMA link up
+ * @link_fault: PCS link fault
+ * @in_reset: XPCS in reset
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_signal_detect {
+ u8 port_id:2;
+ u8 rx_signal:1;
+ u8 pma_link:1;
+ u8 link_fault:1;
+ u8 in_reset:1;
+ u8 __rsv:2;
+ u8 __pad;
+ __le16 result;
+} __packed;
+
#endif /* __MXL862XX_API_H */
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -83,6 +83,8 @@
#define MXL862XX_XPCS_FORCE_SPEED (MXL862XX_XPCS_MAGIC + 0x7)
@@ -79,6 +79,7 @@
#define MXL862XX_XPCS_PCS_LINK_UP (MXL862XX_XPCS_MAGIC + 0x7)
#define MXL862XX_XPCS_LOOPBACK (MXL862XX_XPCS_MAGIC + 0x8)
#define MXL862XX_XPCS_RESET (MXL862XX_XPCS_MAGIC + 0x9)
+#define MXL862XX_XPCS_EQ_GET (MXL862XX_XPCS_MAGIC + 0xc)
+#define MXL862XX_XPCS_SIGNAL_DETECT (MXL862XX_XPCS_MAGIC + 0xd)
#define MMD_API_MAXIMUM_ID 0x7fff
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
@@ -439,3 +439,96 @@ const struct phylink_mac_ops mxl862xx_ph
@@ -401,3 +401,100 @@ const struct phylink_mac_ops mxl862xx_ph
.mac_link_up = mxl862xx_phylink_mac_link_up,
.mac_select_pcs = mxl862xx_phylink_mac_select_pcs,
};
@@ -152,18 +153,19 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ "serdes_rx_dfe_bypass",
+ "serdes_rx_adapt_mode",
+ "serdes_rx_adapt_sel",
+ "serdes_rx_signal",
+ "serdes_pma_link",
+ "serdes_link_fault",
+ "serdes_in_reset",
+};
+
+static bool mxl862xx_port_has_serdes_stats(struct dsa_switch *ds, int port)
+{
+ struct mxl862xx_priv *priv = ds->priv;
+
+ return port >= 9 && port <= 16 &&
+ MXL862XX_FW_VER_MIN(priv, 1, 0, 80);
+ /* Firmware reads EQ/signal status per XPCS, not per lane. Expose
+ * the stats only on the slot-0 port of each XPCS (9 and 13) so
+ * users don't see four duplicate copies labelled as if they were
+ * independent per-port readings.
+ */
+ return (port == 9 || port == 13) &&
+ MXL862XX_FW_VER_MIN(priv, 1, 0, 84);
+}
+
+int mxl862xx_serdes_stats_count(struct dsa_switch *ds, int port)
@@ -185,50 +187,53 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ ethtool_puts(&data, mxl862xx_serdes_stats[i]);
+}
+
+static u64 mxl862xx_eq_effective(const struct mxl862xx_xpcs_eq_item *it)
+{
+ return it->ovrd_en ? it->ovrd : it->value;
+}
+
+void mxl862xx_serdes_get_stats(struct dsa_switch *ds, int port, u64 *data)
+{
+ struct mxl862xx_xpcs_eq_get eq = {
+ .port_id = mxl862xx_xpcs_port_id(port),
+ .port_id = MXL862XX_SERDES_PORT_ID(port),
+ };
+ struct mxl862xx_xpcs_signal_detect sig = {};
+ int ret;
+
+ if (!mxl862xx_port_has_serdes_stats(ds, port))
+ return;
+
+ sig.port_id = mxl862xx_xpcs_port_id(port);
+
+ if (!MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_EQ_GET, eq)) {
+ *data++ = eq.tx.main.value;
+ *data++ = eq.tx.pre.value;
+ *data++ = eq.tx.post.value;
+ *data++ = eq.tx.iboost_lvl.value;
+ *data++ = eq.tx.vboost_lvl.value;
+ *data++ = eq.tx.vboost_en.value;
+ *data++ = eq.rx.att_lvl.value;
+ *data++ = eq.rx.vga1_gain.value;
+ *data++ = eq.rx.vga2_gain.value;
+ *data++ = eq.rx.ctle_boost.value;
+ *data++ = eq.rx.ctle_pole.value;
+ *data++ = eq.rx.dfe_tap1.value;
+ *data++ = eq.rx.dfe_bypass.value;
+ *data++ = eq.rx.adapt_mode.value;
+ *data++ = eq.rx.adapt_sel.value;
+ } else {
+ data += 15;
+ ret = MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_EQ_GET, eq);
+ if (ret) {
+ dev_err(ds->dev,
+ "port %d: XPCS EQ_GET failed: %d\n", port, ret);
+ return;
+ }
+ if ((s16)le16_to_cpu(eq.result) < 0) {
+ dev_err(ds->dev,
+ "port %d: XPCS EQ_GET firmware result: %d\n",
+ port, (s16)le16_to_cpu(eq.result));
+ return;
+ }
+
+ if (!MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_SIGNAL_DETECT, sig)) {
+ *data++ = sig.rx_signal;
+ *data++ = sig.pma_link;
+ *data++ = sig.link_fault;
+ *data++ = sig.in_reset;
+ } else {
+ data += 4;
+ }
+ *data++ = mxl862xx_eq_effective(&eq.tx.main);
+ *data++ = mxl862xx_eq_effective(&eq.tx.pre);
+ *data++ = mxl862xx_eq_effective(&eq.tx.post);
+ *data++ = mxl862xx_eq_effective(&eq.tx.iboost_lvl);
+ *data++ = mxl862xx_eq_effective(&eq.tx.vboost_lvl);
+ *data++ = mxl862xx_eq_effective(&eq.tx.vboost_en);
+ *data++ = mxl862xx_eq_effective(&eq.rx.att_lvl);
+ *data++ = mxl862xx_eq_effective(&eq.rx.vga1_gain);
+ *data++ = mxl862xx_eq_effective(&eq.rx.vga2_gain);
+ *data++ = mxl862xx_eq_effective(&eq.rx.ctle_boost);
+ *data++ = mxl862xx_eq_effective(&eq.rx.ctle_pole);
+ *data++ = mxl862xx_eq_effective(&eq.rx.dfe_tap1);
+ *data++ = mxl862xx_eq_effective(&eq.rx.dfe_bypass);
+ *data++ = mxl862xx_eq_effective(&eq.rx.adapt_mode);
+ *data++ = mxl862xx_eq_effective(&eq.rx.adapt_sel);
+}
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
@@ -12,5 +12,8 @@ void mxl862xx_phylink_get_caps(struct ds
@@ -17,5 +17,8 @@ void mxl862xx_phylink_get_caps(struct ds
struct phylink_config *config);
void mxl862xx_setup_pcs(struct mxl862xx_priv *priv, struct mxl862xx_pcs *pcs,
int port);
@@ -239,7 +244,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#endif /* __MXL862XX_PHYLINK_H */
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -1775,6 +1775,8 @@ static void mxl862xx_get_strings(struct
@@ -1776,6 +1776,8 @@ static void mxl862xx_get_strings(struct
for (i = 0; i < ARRAY_SIZE(mxl862xx_mib); i++)
ethtool_puts(&data, mxl862xx_mib[i].name);
@@ -248,7 +253,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
static int mxl862xx_get_sset_count(struct dsa_switch *ds, int port, int sset)
@@ -1782,7 +1784,7 @@ static int mxl862xx_get_sset_count(struc
@@ -1783,7 +1785,7 @@ static int mxl862xx_get_sset_count(struc
if (sset != ETH_SS_STATS)
return 0;
@@ -257,7 +262,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
static int mxl862xx_read_rmon(struct dsa_switch *ds, int port,
@@ -1818,6 +1820,8 @@ static void mxl862xx_get_ethtool_stats(s
@@ -1819,6 +1821,8 @@ static void mxl862xx_get_ethtool_stats(s
else
*data++ = le64_to_cpu(*(__le64 *)field);
}
@@ -1,208 +0,0 @@
From ce66c0be462c8500dfc483395e68be4326ebf296 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:15:32 +0000
Subject: [PATCH 06/19] net: dsa: mxl862xx: add SerDes self-test via PRBS and
BERT
Implement the dsa_switch_ops.self_test callback for SerDes ports
(9-16). Two loopback tests are run:
1. PCS-level PRBS31: enables TX/RX PRBS31 pattern at the PCS layer,
waits 100ms, then reads the error counter.
2. SerDes-level BERT PRBS31: enables TX/RX BERT with PRBS31 pattern
at the SerDes layer, waits 100ms, then reads the error counter.
Both tests clean up (disable pattern generators) regardless of outcome.
Gated on firmware >= 1.0.80 via mxl862xx_port_has_serdes_stats().
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 45 +++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 85 +++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 1 +
5 files changed, 136 insertions(+)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -1900,4 +1900,49 @@ struct mxl862xx_xpcs_signal_detect {
__le16 result;
} __packed;
+/**
+ * struct mxl862xx_xpcs_prbs_cfg - PCS-level PRBS31 test pattern
+ * @port_id: XPCS port index (0 or 1)
+ * @tx_en: TX PRBS31 enable
+ * @rx_en: RX PRBS31 enable
+ * @read_err: read error count
+ * @rx_err_cnt: RX PRBS31 error count (valid when read_err=1)
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_prbs_cfg {
+ u8 port_id:2;
+ u8 tx_en:1;
+ u8 rx_en:1;
+ u8 read_err:1;
+ u8 __rsv:3;
+ u8 __pad;
+ __le16 rx_err_cnt;
+ __le16 result;
+} __packed;
+
+/**
+ * struct mxl862xx_xpcs_bert_cfg - SerDes-level BERT test pattern
+ * @port_id: XPCS port index (0 or 1)
+ * @tx_en: TX BERT enable
+ * @rx_en: RX BERT enable
+ * @read_err: read RX error count
+ * @clear_err: clear RX error counter
+ * @insert_err: insert one TX error
+ * @pattern: PRBS pattern type (1-7; 0 = disable)
+ * @rx_err_cnt: RX BERT error count (valid when read_err=1)
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_bert_cfg {
+ u8 port_id:2;
+ u8 tx_en:1;
+ u8 rx_en:1;
+ u8 read_err:1;
+ u8 clear_err:1;
+ u8 insert_err:1;
+ u8 __rsv:1;
+ u8 pattern;
+ __le16 rx_err_cnt;
+ __le16 result;
+} __packed;
+
#endif /* __MXL862XX_API_H */
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -83,6 +83,8 @@
#define MXL862XX_XPCS_FORCE_SPEED (MXL862XX_XPCS_MAGIC + 0x7)
#define MXL862XX_XPCS_LOOPBACK (MXL862XX_XPCS_MAGIC + 0x8)
#define MXL862XX_XPCS_RESET (MXL862XX_XPCS_MAGIC + 0x9)
+#define MXL862XX_XPCS_PRBS_CFG (MXL862XX_XPCS_MAGIC + 0xa)
+#define MXL862XX_XPCS_BERT_CFG (MXL862XX_XPCS_MAGIC + 0xb)
#define MXL862XX_XPCS_EQ_GET (MXL862XX_XPCS_MAGIC + 0xc)
#define MXL862XX_XPCS_SIGNAL_DETECT (MXL862XX_XPCS_MAGIC + 0xd)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
@@ -532,3 +532,88 @@ void mxl862xx_serdes_get_stats(struct ds
data += 4;
}
}
+
+void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
+ struct ethtool_test *etest, u64 *data)
+{
+ struct mxl862xx_xpcs_prbs_cfg prbs = {};
+ struct mxl862xx_xpcs_bert_cfg bert = {};
+ struct mxl862xx_priv *priv = ds->priv;
+ int xpcs_id = mxl862xx_xpcs_port_id(port);
+ int i = 0;
+ int ret;
+
+ if (!mxl862xx_port_has_serdes_stats(ds, port))
+ return;
+
+ /* Test 1: PCS PRBS31 */
+ prbs.port_id = xpcs_id;
+ prbs.tx_en = 1;
+ prbs.rx_en = 1;
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
+ if (ret) {
+ data[i++] = 1;
+ goto skip_prbs;
+ }
+
+ msleep(100);
+
+ memset(&prbs, 0, sizeof(prbs));
+ prbs.port_id = xpcs_id;
+ prbs.read_err = 1;
+ ret = MXL862XX_API_READ(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
+
+ /* Disable PRBS */
+ memset(&prbs, 0, sizeof(prbs));
+ prbs.port_id = xpcs_id;
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
+
+ if (ret) {
+ data[i++] = 1;
+ } else {
+ data[i] = le16_to_cpu(prbs.rx_err_cnt) ? 1 : 0;
+ if (data[i])
+ etest->flags |= ETH_TEST_FL_FAILED;
+ i++;
+ }
+
+skip_prbs:
+ /* Test 2: SerDes BERT PRBS31 -- clear error counter first */
+ bert.port_id = xpcs_id;
+ bert.clear_err = 1;
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
+
+ /* Enable BERT with PRBS31 pattern */
+ memset(&bert, 0, sizeof(bert));
+ bert.port_id = xpcs_id;
+ bert.tx_en = 1;
+ bert.rx_en = 1;
+ bert.pattern = 6; /* PRBS31 */
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
+ if (ret) {
+ data[i++] = 1;
+ return;
+ }
+
+ msleep(100);
+
+ /* Read error count */
+ memset(&bert, 0, sizeof(bert));
+ bert.port_id = xpcs_id;
+ bert.read_err = 1;
+ ret = MXL862XX_API_READ(priv, MXL862XX_XPCS_BERT_CFG, bert);
+
+ /* Disable BERT */
+ memset(&bert, 0, sizeof(bert));
+ bert.port_id = xpcs_id;
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
+
+ if (ret) {
+ data[i++] = 1;
+ } else {
+ data[i] = le16_to_cpu(bert.rx_err_cnt) ? 1 : 0;
+ if (data[i])
+ etest->flags |= ETH_TEST_FL_FAILED;
+ i++;
+ }
+}
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
@@ -3,6 +3,7 @@
#ifndef __MXL862XX_PHYLINK_H
#define __MXL862XX_PHYLINK_H
+#include <linux/ethtool.h>
#include <linux/phylink.h>
#include "mxl862xx.h"
@@ -15,5 +16,7 @@ void mxl862xx_setup_pcs(struct mxl862xx_
int mxl862xx_serdes_stats_count(struct dsa_switch *ds, int port);
void mxl862xx_serdes_get_strings(struct dsa_switch *ds, int port, u8 *data);
void mxl862xx_serdes_get_stats(struct dsa_switch *ds, int port, u64 *data);
+void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
+ struct ethtool_test *etest, u64 *data);
#endif /* __MXL862XX_PHYLINK_H */
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -2088,6 +2088,7 @@ static const struct dsa_switch_ops mxl86
.get_pause_stats = mxl862xx_get_pause_stats,
.get_rmon_stats = mxl862xx_get_rmon_stats,
.get_stats64 = mxl862xx_get_stats64,
+ .self_test = mxl862xx_serdes_self_test,
};
static int mxl862xx_probe(struct mdio_device *mdiodev)
@@ -1,7 +1,7 @@
From e6defbd42db6e64c2bb203f82b7d7f8c0691a052 Mon Sep 17 00:00:00 2001
From 50a84327282120a51af12da91214ed9e06f585cb Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:51:13 +0000
Subject: [PATCH 07/19] net: dsa: mxl862xx: trap link-local and multicast
Subject: [PATCH 06/19] net: dsa: mxl862xx: trap link-local and multicast
snooping frames to CPU
Install per-CTP PCE rules on each user port that trap IEEE 802.1D
@@ -19,10 +19,21 @@ all flood modes enabled. Each trap rule points the bridge engine at
this FID via bFidEnable so that IGMP and MLD frames are never
silently dropped by the ingress port's private flood policy.
Three multicast snooping rules are installed per port:
offset 2 -- IPv4 IGMP (IP protocol 2, all versions)
offset 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
offset 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
Rules are written through the firmware's logical-index API,
GSW_TFLOW_PCERULELOGICWRITE. The firmware translates the logical
index in @rule->pattern.index into a physical position within the
per-CTP block selected by @rule->region and @rule->logicalportid,
and grows the hardware block size on demand as rules are inserted.
A single dispatch helper, mxl862xx_pce_rule_write(), centralises the
firmware command so the trap callers do not need to know which API
variant is used. Four logical indices are consumed in each port's
per-CTP block (index 0 is reserved by the firmware for its
flow-control marking rule):
index 1 -- IEEE 802.1D link-local (dst 01:80:c2:00:00:0x)
index 2 -- IPv4 IGMP (IP protocol 2, all versions)
index 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
index 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
Add the PCE rule firmware API structures, command definitions, and
the rule block allocation interface.
@@ -30,15 +41,15 @@ the rule block allocation interface.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 684 ++++++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 5 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 186 +++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 6 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 198 +++++++
drivers/net/dsa/mxl862xx/mxl862xx.h | 8 +
4 files changed, 883 insertions(+)
4 files changed, 896 insertions(+)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -1420,6 +1420,690 @@ struct mxl862xx_port_link_cfg {
u8 lpi;
@@ -1184,6 +1184,690 @@ struct mxl862xx_ctp_port_assignment {
__le16 bridge_port_id;
} __packed;
+/* PCE (Packet Classification Engine) rule structures.
@@ -694,7 +705,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * @action: Forwarding action (portmap, cross-state, etc.)
+ *
+ * This structure is passed to the firmware via the MDIO data
+ * buffer using the %MXL862XX_TFLOW_PCERULEWRITE command.
+ * buffer using the %MXL862XX_TFLOW_PCERULELOGICWRITE command.
+ * The binary layout must exactly match the firmware's
+ * GSW_PCE_rule_t (466 bytes, packed, little-endian scalars).
+ */
@@ -738,13 +749,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#define MXL862XX_BRDG_MAGIC 0x300
#define MXL862XX_BRDGPORT_MAGIC 0x400
#define MXL862XX_CTP_MAGIC 0x500
@@ -31,6 +32,10 @@
@@ -30,6 +31,11 @@
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
+#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
+#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
+#define MXL862XX_TFLOW_PCERULEFREE (MXL862XX_TFLOW_MAGIC + 0x5)
+#define MXL862XX_TFLOW_PCERULELOGICWRITE \
+ (MXL862XX_TFLOW_MAGIC + 0xa)
+
#define MXL862XX_BRIDGE_ALLOC (MXL862XX_BRDG_MAGIC + 0x1)
#define MXL862XX_BRIDGE_CONFIGSET (MXL862XX_BRDG_MAGIC + 0x2)
@@ -771,21 +783,35 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return 0;
not_ready_yet:
@@ -381,6 +384,158 @@ static int mxl862xx_setup_drop_meter(str
@@ -381,6 +384,170 @@ static int mxl862xx_setup_drop_meter(str
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
}
+
+/* Per-CTP offsets for protocol trap rules. Each port's CTP flow-table
+ * block is pre-allocated by the firmware during init (44 entries per
+ * port on a 10-port SKU, of which offset 0 is reserved for flow-control
+ * marking). Offsets 1-4 are used for link-local and multicast snooping
+ * traps; all others remain free.
+/* Per-CTP logical indices for protocol trap rules.
+ *
+ * The firmware pre-allocates a per-CTP PCE block for every port during
+ * init and reserves logical index 0 for its flow-control marking rule.
+ * Logical indices 1-4 are used here for link-local and multicast
+ * snooping traps; the firmware grows the underlying hardware block on
+ * demand as PCERULELOGICWRITE inserts new entries.
+ */
+#define MXL862XX_LINK_LOCAL_CTP_OFFSET 1
+#define MXL862XX_IGMP_CTP_OFFSET 2
+#define MXL862XX_MLDV1_CTP_OFFSET 3
+#define MXL862XX_MLDV2_CTP_OFFSET 4
+#define MXL862XX_LINK_LOCAL_CTP_INDEX 1
+#define MXL862XX_IGMP_CTP_INDEX 2
+#define MXL862XX_MLDV1_CTP_INDEX 3
+#define MXL862XX_MLDV2_CTP_INDEX 4
+
+/* Install (or overwrite) a PCE rule via the firmware's logical-index
+ * API. The firmware translates the logical index in @rule->pattern.index
+ * to a physical position within the block selected by @rule->region and
+ * @rule->logicalportid, and expands the hardware block size as needed.
+ */
+static int mxl862xx_pce_rule_write(struct mxl862xx_priv *priv,
+ struct mxl862xx_pce_rule *rule)
+{
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULELOGICWRITE,
+ *rule);
+}
+
+/* Fill the action fields of a PCE rule that traps ingress frames to
+ * the CPU port. Used by both the link-local trap and the multicast
@@ -826,12 +852,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * The firmware does not install this rule by default because its own
+ * STP module is not used when DSA manages STP.
+ *
+ * The rule is written into the port's per-CTP flow table at offset 1.
+ * The firmware already allocates a 44-entry block for every CTP during
+ * init (8 entries exposed initially, expandable), so no dynamic
+ * allocation via PCERULEALLOC is needed. Using region=CTP causes the
+ * firmware to translate the CTP-relative offset into an absolute
+ * hardware index.
+ * The rule is written into the port's per-CTP flow table at logical
+ * index 1 using PCERULELOGICWRITE, which selects the per-CTP block via
+ * @region and @logicalportid and grows the block on demand.
+ *
+ * Cross-state is enabled so that link-local frames reach the CPU even
+ * when the bridge port is in BLOCKING or LEARNING state.
@@ -844,7 +867,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ rule.logicalportid = port;
+ rule.region = cpu_to_le32(MXL862XX_PCE_RULE_CTP);
+
+ rule.pattern.index = cpu_to_le16(MXL862XX_LINK_LOCAL_CTP_OFFSET);
+ rule.pattern.index = cpu_to_le16(MXL862XX_LINK_LOCAL_CTP_INDEX);
+ rule.pattern.enable = 1;
+ rule.pattern.mac_dst_enable = 1;
+ memcpy(rule.pattern.mac_dst, eth_reserved_addr_base, ETH_ALEN);
@@ -852,7 +875,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
+
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
+ return mxl862xx_pce_rule_write(priv, &rule);
+}
+
+/* Install PCE rules that trap IGMP and MLD frames to the CPU port for
@@ -862,10 +885,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * never classified as blocked unknown MC regardless of the ingress
+ * port's standalone flood policy.
+ *
+ * Three rules are installed per port:
+ * offset 2 -- IPv4 IGMP (IP protocol 2, all versions)
+ * offset 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
+ * offset 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
+ * Three rules are installed per port at logical indices in the per-CTP
+ * block:
+ * index 2 -- IPv4 IGMP (IP protocol 2, all versions)
+ * index 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
+ * index 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
+ *
+ * The MLDv1 rule uses range mode on the first two bytes after the IP
+ * header (ICMPv6 type + code): lower bound 0x8200 (type 130, code 0)
@@ -883,12 +907,12 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
+
+ /* IGMP: IPv4 protocol 2, all versions */
+ rule.pattern.index = cpu_to_le16(MXL862XX_IGMP_CTP_OFFSET);
+ rule.pattern.index = cpu_to_le16(MXL862XX_IGMP_CTP_INDEX);
+ rule.pattern.enable = 1;
+ rule.pattern.protocol = IPPROTO_IGMP;
+ rule.pattern.protocol_enable = 1;
+
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
+ ret = mxl862xx_pce_rule_write(priv, &rule);
+ if (ret)
+ return ret;
+
@@ -896,7 +920,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * Range mode covers all three types with any code value.
+ */
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV1_CTP_OFFSET);
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV1_CTP_INDEX);
+ rule.pattern.enable = 1;
+ rule.pattern.protocol = IPPROTO_ICMPV6;
+ rule.pattern.protocol_enable = 1;
@@ -907,7 +931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ rule.pattern.app_data_msb_enable = 1;
+ rule.pattern.app_mask_range_msb_select = 1; /* range mode */
+
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
+ ret = mxl862xx_pce_rule_write(priv, &rule);
+ if (ret)
+ return ret;
+
@@ -915,7 +939,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * Nibble mask 0x3 masks nibbles 0-1 (lower byte = code field).
+ */
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV2_CTP_OFFSET);
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV2_CTP_INDEX);
+ rule.pattern.enable = 1;
+ rule.pattern.protocol = IPPROTO_ICMPV6;
+ rule.pattern.protocol_enable = 1;
@@ -924,13 +948,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ rule.pattern.app_data_msb_enable = 1;
+ /* app_mask_range_msb_select = 0: nibble mask mode (default) */
+
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
+ return mxl862xx_pce_rule_write(priv, &rule);
+}
+
static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
{
struct mxl862xx_bridge_port_config br_port_cfg = {};
@@ -683,6 +838,28 @@ static int mxl862xx_setup(struct dsa_swi
@@ -684,6 +851,28 @@ static int mxl862xx_setup(struct dsa_swi
if (ret)
return ret;
@@ -959,7 +983,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
schedule_delayed_work(&priv->stats_work,
MXL862XX_STATS_POLL_INTERVAL);
@@ -1382,6 +1559,15 @@ static int mxl862xx_port_setup(struct ds
@@ -1383,6 +1572,15 @@ static int mxl862xx_port_setup(struct ds
if (ret)
return ret;
@@ -977,7 +1001,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -319,6 +319,13 @@ union mxl862xx_fw_version {
@@ -317,6 +317,13 @@ struct mxl862xx_fw_version {
* @evlan_ingress_size: per-port ingress Extended VLAN block size
* @evlan_egress_size: per-port egress Extended VLAN block size
* @vf_block_size: per-port VLAN Filter block size
@@ -991,7 +1015,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @stats_work: periodic work item that polls RMON hardware counters
* and accumulates them into 64-bit per-port stats
*/
@@ -335,6 +342,7 @@ struct mxl862xx_priv {
@@ -334,6 +341,7 @@ struct mxl862xx_priv {
u16 evlan_ingress_size;
u16 evlan_egress_size;
u16 vf_block_size;
@@ -1,7 +1,7 @@
From 264838ee8ee3ad611a84df96d889429f1ded2148 Mon Sep 17 00:00:00 2001
From 6126dff8c28e71091c23fd0cc2f55b1a50e117a6 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:51:21 +0000
Subject: [PATCH 08/19] net: dsa: mxl862xx: warn about old firmware default PCE
Subject: [PATCH 07/19] net: dsa: mxl862xx: warn about old firmware default PCE
rules
Firmware versions older than 1.0.80 install global PCE rules at
@@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -860,6 +860,10 @@ static int mxl862xx_setup(struct dsa_swi
@@ -873,6 +873,10 @@ static int mxl862xx_setup(struct dsa_swi
true, true, true);
if (ret)
return ret;
@@ -1,7 +1,7 @@
From d7ed9b681298d206d81e9cf3c93558d6e912ae88 Mon Sep 17 00:00:00 2001
From 69a0946ef48325b85f4a331152d6340f39083053 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Sun, 22 Mar 2026 00:58:04 +0000
Subject: [PATCH 09/20] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx
Subject: [PATCH 08/19] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx
The MxL862xx native 8-byte special tag (SpTag) requires firmware
support on the switch CPU and is not compatible with all SoC Ethernet
@@ -22,13 +22,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
drivers/net/dsa/mxl862xx/Kconfig | 1 +
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 221 +++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 1678 ++++++++++++++++++++---
drivers/net/dsa/mxl862xx/mxl862xx.c | 1677 ++++++++++++++++++++---
drivers/net/dsa/mxl862xx/mxl862xx.h | 12 +
include/net/dsa.h | 2 +
net/dsa/Kconfig | 7 +
net/dsa/Makefile | 1 +
net/dsa/tag_mxl862xx_8021q.c | 65 +
9 files changed, 1803 insertions(+), 186 deletions(-)
9 files changed, 1804 insertions(+), 184 deletions(-)
create mode 100644 net/dsa/tag_mxl862xx_8021q.c
--- a/drivers/net/dsa/mxl862xx/Kconfig
@@ -43,10 +43,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
These switches have two 10GE SerDes interfaces, one typically
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -1185,6 +1185,227 @@ struct mxl862xx_ctp_port_assignment {
@@ -1184,6 +1184,227 @@ struct mxl862xx_ctp_port_assignment {
__le16 bridge_port_id;
} __packed;
/**
+/**
+ * enum mxl862xx_ctp_port_config_mask - CTP Port Configuration Mask
+ * @MXL862XX_CTP_PORT_CONFIG_MASK_BRIDGE_PORT_ID:
+ * Mask for bridge_port_id.
@@ -267,10 +268,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ u8 egress_mirror_enable;
+} __packed;
+
+/**
* enum mxl862xx_port_duplex - Ethernet port duplex status
* @MXL862XX_DUPLEX_FULL: Port operates in full-duplex mode
* @MXL862XX_DUPLEX_HALF: Port operates in half-duplex mode
/* PCE (Packet Classification Engine) rule structures.
*
* Binary layout must exactly match the firmware's GSW_PCE_rule_t
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -47,12 +47,14 @@
@@ -387,9 +387,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
/* PHY access via firmware relay */
@@ -396,6 +459,78 @@ static int mxl862xx_setup_drop_meter(str
#define MXL862XX_MLDV1_CTP_OFFSET 3
#define MXL862XX_MLDV2_CTP_OFFSET 4
@@ -410,6 +473,78 @@ static int mxl862xx_pce_rule_write(struc
*rule);
}
+/**
+ * mxl862xx_cpu_bridge_port_id - Get the bridge port ID for CPU-side forwarding
@@ -466,7 +466,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
/* Fill the action fields of a PCE rule that traps ingress frames to
* the CPU port. Used by both the link-local trap and the multicast
* snooping traps. The caller must already have set the rule header
@@ -404,24 +539,36 @@ static int mxl862xx_setup_drop_meter(str
@@ -418,24 +553,36 @@ static int mxl862xx_pce_rule_write(struc
* PORTMAP_ALTERNATIVE redirects the frame to the CPU port but does
* not by itself bypass downstream flood gates. In SpTag mode the
* ingress port's private FID may have forward_unknown_multicast=false,
@@ -505,17 +505,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
rule->action.cross_state_action =
cpu_to_le32(MXL862XX_PCE_ACTION_CROSS_STATE_CROSS);
@@ -441,9 +588,6 @@ static void mxl862xx_fill_cpu_trap_actio
* allocation via PCERULEALLOC is needed. Using region=CTP causes the
* firmware to translate the CTP-relative offset into an absolute
* hardware index.
- *
- * Cross-state is enabled so that link-local frames reach the CPU even
- * when the bridge port is in BLOCKING or LEARNING state.
*/
static int mxl862xx_setup_link_local_trap(struct dsa_switch *ds, int port)
{
@@ -552,11 +696,17 @@ static int mxl862xx_set_bridge_port(stru
@@ -564,11 +711,17 @@ static int mxl862xx_set_bridge_port(stru
return 0;
if (dsa_port_is_cpu(dp)) {
@@ -538,7 +528,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
} else if (dp->bridge) {
dsa_switch_for_each_bridge_member(member_dp, ds,
@@ -567,10 +717,10 @@ static int mxl862xx_set_bridge_port(stru
@@ -579,10 +732,10 @@ static int mxl862xx_set_bridge_port(stru
member_dp->index);
}
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
@@ -551,7 +541,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
p->flood_block = 0;
p->learning = false;
}
@@ -774,10 +924,12 @@ static void mxl862xx_free_bridge(struct
@@ -786,10 +939,12 @@ static void mxl862xx_free_bridge(struct
static int mxl862xx_setup(struct dsa_switch *ds)
{
struct mxl862xx_priv *priv = ds->priv;
@@ -566,16 +556,16 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = mxl862xx_reset(priv);
if (ret)
@@ -790,7 +942,7 @@ static int mxl862xx_setup(struct dsa_swi
for (i = 0; i < 8; i++)
mxl862xx_setup_pcs(priv, &priv->serdes_ports[i], i + 9);
@@ -803,7 +958,7 @@ static int mxl862xx_setup(struct dsa_swi
mxl862xx_setup_pcs(priv, &priv->serdes_ports[i],
i + MXL862XX_FIRST_SERDES_PORT);
- /* Calculate Extended VLAN block sizes.
+ /* Calculate Extended VLAN and VLAN Filter block sizes.
* With VLAN Filter handling VID membership checks:
* Ingress: only final catchall rules (PVID insertion, 802.1Q
* accept, non-8021Q TPID handling, discard).
@@ -798,46 +950,151 @@ static int mxl862xx_setup(struct dsa_swi
@@ -811,46 +966,151 @@ static int mxl862xx_setup(struct dsa_swi
* ingress EVLAN rules are needed. (7 entries.)
* Egress: 2 rules per VID that needs tag stripping (untagged VIDs).
* No egress final catchalls -- VLAN Filter does the discard.
@@ -739,7 +729,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
/* Allocate a dedicated PCE snooping FID with all flood modes enabled.
* Per-port PCE trap rules (link-local, IGMP, MLD) set bFidEnable to
@@ -860,10 +1117,6 @@ static int mxl862xx_setup(struct dsa_swi
@@ -873,10 +1133,6 @@ static int mxl862xx_setup(struct dsa_swi
true, true, true);
if (ret)
return ret;
@@ -750,7 +740,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
schedule_delayed_work(&priv->stats_work,
MXL862XX_STATS_POLL_INTERVAL);
@@ -944,10 +1197,71 @@ static int mxl862xx_configure_sp_tag_pro
@@ -957,10 +1213,71 @@ static int mxl862xx_configure_sp_tag_pro
return MXL862XX_API_WRITE(ds->priv, MXL862XX_SS_SPTAG_SET, tag);
}
@@ -823,7 +813,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
{
struct mxl862xx_extendedvlan_config cfg = {};
struct mxl862xx_extendedvlan_filter_vlan *fv;
@@ -1016,6 +1330,31 @@ static int mxl862xx_evlan_write_rule(str
@@ -1029,6 +1346,31 @@ static int mxl862xx_evlan_write_rule(str
cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM);
}
break;
@@ -855,7 +845,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
return MXL862XX_API_WRITE(priv, MXL862XX_EXTENDEDVLAN_SET, cfg);
@@ -1054,7 +1393,7 @@ static int mxl862xx_evlan_write_final_ru
@@ -1067,7 +1409,7 @@ static int mxl862xx_evlan_write_final_ru
for (i = 0; i < n_rules; i++) {
ret = mxl862xx_evlan_write_rule(priv, blk->block_id,
start_idx + i, &rules[i],
@@ -864,7 +854,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
}
@@ -1175,6 +1514,41 @@ static int mxl862xx_vf_del_vid(struct mx
@@ -1188,6 +1530,41 @@ static int mxl862xx_vf_del_vid(struct mx
return 0;
}
@@ -906,7 +896,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int mxl862xx_evlan_program_ingress(struct mxl862xx_priv *priv, int port)
{
struct mxl862xx_port *p = &priv->ports[port];
@@ -1199,8 +1573,8 @@ static int mxl862xx_evlan_program_egress
@@ -1212,8 +1589,8 @@ static int mxl862xx_evlan_program_egress
const struct mxl862xx_evlan_rule_desc *vid_rules;
struct mxl862xx_vf_vid *vfv;
u16 old_active = blk->n_active;
@@ -916,7 +906,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (p->vlan_filtering) {
vid_rules = vid_accept_standard;
@@ -1214,13 +1588,23 @@ static int mxl862xx_evlan_program_egress
@@ -1227,13 +1604,23 @@ static int mxl862xx_evlan_program_egress
if (!vfv->untagged)
continue;
@@ -941,7 +931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
@@ -1229,7 +1613,29 @@ static int mxl862xx_evlan_program_egress
@@ -1242,7 +1629,29 @@ static int mxl862xx_evlan_program_egress
idx++, &vid_rules[1],
vfv->vid,
vfv->untagged,
@@ -972,7 +962,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
}
@@ -1241,8 +1647,7 @@ static int mxl862xx_evlan_program_egress
@@ -1254,8 +1663,7 @@ static int mxl862xx_evlan_program_egress
*/
for (i = idx; i < old_active; i++) {
ret = mxl862xx_evlan_deactivate_entry(priv,
@@ -982,7 +972,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
}
@@ -1267,13 +1672,16 @@ static int mxl862xx_port_vlan_filtering(
@@ -1280,13 +1688,16 @@ static int mxl862xx_port_vlan_filtering(
p->vlan_filtering = vlan_filtering;
if (changed) {
@@ -1004,7 +994,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = mxl862xx_evlan_program_ingress(priv, port);
if (ret)
@@ -1493,22 +1901,575 @@ static void mxl862xx_port_bridge_leave(s
@@ -1506,22 +1917,575 @@ static void mxl862xx_port_bridge_leave(s
port, ERR_PTR(err));
/* Revert leaving port, omitted by the sync above, to its
@@ -1582,7 +1572,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int mxl862xx_port_setup(struct dsa_switch *ds, int port)
{
struct mxl862xx_priv *priv = ds->priv;
@@ -1530,33 +2491,52 @@ static int mxl862xx_port_setup(struct ds
@@ -1543,33 +2507,52 @@ static int mxl862xx_port_setup(struct ds
return -EOPNOTSUPP;
}
@@ -1651,7 +1641,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
ret = mxl862xx_set_bridge_port(ds, port);
@@ -1572,24 +2552,7 @@ static int mxl862xx_port_setup(struct ds
@@ -1585,24 +2568,7 @@ static int mxl862xx_port_setup(struct ds
if (ret)
return ret;
@@ -1676,7 +1666,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return 0;
}
@@ -1611,7 +2574,7 @@ static void mxl862xx_port_teardown(struc
@@ -1624,7 +2590,7 @@ static void mxl862xx_port_teardown(struc
priv->ports[port].setup_done = false;
}
@@ -1685,7 +1675,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
{
struct mxl862xx_priv *priv = ds->priv;
@@ -1629,23 +2592,247 @@ static int mxl862xx_get_fid(struct dsa_s
@@ -1642,23 +2608,247 @@ static int mxl862xx_get_fid(struct dsa_s
}
}
@@ -1718,12 +1708,12 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ if (dsa_is_cpu_port(ds, port) && priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q &&
+ db.type == DSA_DB_PORT) {
+ bp_cpu = priv->ports[db.dp->index].bridge_port_cpu;
+
- param.port_id = cpu_to_le32(port);
+ if (bp_cpu)
+ return bp_cpu;
+ }
- param.port_id = cpu_to_le32(port);
+
+ return port;
+}
+
@@ -1941,7 +1931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
dev_err(ds->dev, "failed to add FDB entry on port %d\n", port);
@@ -1655,18 +2842,25 @@ static int mxl862xx_port_fdb_add(struct
@@ -1668,18 +2858,25 @@ static int mxl862xx_port_fdb_add(struct
static int mxl862xx_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid, const struct dsa_db db)
{
@@ -1950,7 +1940,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct mxl862xx_priv *priv = ds->priv;
+ struct dsa_port *target_dp;
+ int fid, ret;
+
+ /* Mirror of the standalone->bridge FID path in fdb_add */
+ if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && dsa_is_cpu_port(ds, port) &&
+ db.type == DSA_DB_PORT && vid > 0) {
@@ -1960,7 +1950,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ mxl862xx_fdb_del_per_fid(ds, addr, vid,
+ priv->bridges[target_dp->bridge->num]);
+ }
+
+ fid = mxl862xx_get_fid(ds, db);
if (fid < 0)
return fid;
@@ -1974,7 +1964,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
dev_err(ds->dev, "failed to remove FDB entry on port %d\n", port);
@@ -1705,84 +2899,153 @@ static int mxl862xx_port_fdb_dump(struct
@@ -1718,84 +2915,153 @@ static int mxl862xx_port_fdb_dump(struct
return 0;
}
@@ -2075,7 +2065,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
- sizeof(aparam.port_map));
+ return ret;
+}
+
- mxl862xx_fw_portmap_set_bit(aparam.port_map, port);
+/**
+ * mxl862xx_mac_del_host_bridge - Remove every user-port VBP bit from a host
+ * FDB/MDB entry, dropping the entry when its
@@ -2099,14 +2090,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ struct dsa_port *dp;
+ u16 vbp;
- mxl862xx_fw_portmap_set_bit(aparam.port_map, port);
- return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYADD, aparam);
+ dsa_switch_for_each_user_port(dp, ds) {
+ vbp = priv->ports[dp->index].bridge_port_cpu;
+ if (vbp)
+ mxl862xx_fw_portmap_set_bit(del_map, vbp);
+ }
- return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYADD, aparam);
+
+ return mxl862xx_mac_portmap_del(priv, addr, fid, vid, del_map);
}
@@ -2120,7 +2110,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
- int fid = mxl862xx_get_fid(ds, db), ret;
struct mxl862xx_priv *priv = ds->priv;
+ int fid, ret;
+
+ /* tag_8021q host MDB for bridged ports: clear all VBP bits */
+ if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && dsa_is_cpu_port(ds, port) &&
+ db.type == DSA_DB_BRIDGE) {
@@ -2130,7 +2120,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ return mxl862xx_mac_del_host_bridge(ds, mdb->addr,
+ mdb->vid, &db.bridge);
+ }
+
+ fid = mxl862xx_get_fid(ds, db);
if (fid < 0)
return fid;
@@ -2175,7 +2165,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return ret;
}
@@ -1867,6 +3130,9 @@ static void mxl862xx_host_flood_work_fn(
@@ -1880,6 +3146,9 @@ static void mxl862xx_host_flood_work_fn(
host_flood_work);
struct mxl862xx_priv *priv = p->priv;
struct dsa_switch *ds = priv->ds;
@@ -2185,7 +2175,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
rtnl_lock();
@@ -1876,13 +3142,34 @@ static void mxl862xx_host_flood_work_fn(
@@ -1889,13 +3158,34 @@ static void mxl862xx_host_flood_work_fn(
return;
}
@@ -2227,7 +2217,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
rtnl_unlock();
}
@@ -2248,7 +3535,9 @@ static void mxl862xx_get_stats64(struct
@@ -2261,7 +3551,9 @@ static void mxl862xx_get_stats64(struct
static const struct dsa_switch_ops mxl862xx_switch_ops = {
.get_tag_protocol = mxl862xx_get_tag_protocol,
@@ -2237,7 +2227,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.port_setup = mxl862xx_port_setup,
.port_teardown = mxl862xx_port_teardown,
.phylink_get_caps = mxl862xx_phylink_get_caps,
@@ -2270,6 +3559,8 @@ static const struct dsa_switch_ops mxl86
@@ -2283,6 +3575,8 @@ static const struct dsa_switch_ops mxl86
.port_vlan_filtering = mxl862xx_port_vlan_filtering,
.port_vlan_add = mxl862xx_port_vlan_add,
.port_vlan_del = mxl862xx_port_vlan_del,
@@ -2246,7 +2236,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_strings = mxl862xx_get_strings,
.get_sset_count = mxl862xx_get_sset_count,
.get_ethtool_stats = mxl862xx_get_ethtool_stats,
@@ -2318,6 +3609,8 @@ static int mxl862xx_probe(struct mdio_de
@@ -2330,6 +3624,8 @@ static int mxl862xx_probe(struct mdio_de
INIT_DELAYED_WORK(&priv->stats_work, mxl862xx_stats_work_fn);
@@ -2255,7 +2245,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
dev_set_drvdata(dev, ds);
err = dsa_register_switch(ds);
@@ -2346,6 +3639,19 @@ static void mxl862xx_remove(struct mdio_
@@ -2358,6 +3654,19 @@ static void mxl862xx_remove(struct mdio_
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
cancel_delayed_work_sync(&priv->stats_work);
@@ -2277,7 +2267,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
mxl862xx_host_shutdown(priv);
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -209,6 +209,9 @@ struct mxl862xx_port_stats {
@@ -212,6 +212,9 @@ struct mxl862xx_port_stats {
* @vf: per-port VLAN Filter block state
* @ingress_evlan: ingress extended VLAN block state
* @egress_evlan: egress extended VLAN block state
@@ -2287,7 +2277,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @host_flood_uc: desired host unicast flood state (true = flood);
* updated atomically by port_set_host_flood, consumed
* by the deferred host_flood_work
@@ -223,6 +226,7 @@ struct mxl862xx_port_stats {
@@ -226,6 +229,7 @@ struct mxl862xx_port_stats {
* periodically by the stats polling work
* @stats_lock: protects accumulator reads in .get_stats64 against
* concurrent updates from the polling work
@@ -2295,7 +2285,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
*/
struct mxl862xx_port {
struct mxl862xx_priv *priv;
@@ -235,9 +239,13 @@ struct mxl862xx_port {
@@ -238,9 +242,13 @@ struct mxl862xx_port {
struct mxl862xx_vf_block vf;
struct mxl862xx_evlan_block ingress_evlan;
struct mxl862xx_evlan_block egress_evlan;
@@ -2309,7 +2299,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct mxl862xx_port_stats stats;
spinlock_t stats_lock; /* protects stats accumulators */
};
@@ -304,6 +312,7 @@ union mxl862xx_fw_version {
@@ -298,6 +306,7 @@ struct mxl862xx_fw_version {
* before CRC-triggered shutdown and cleared after;
* %MXL862XX_FLAG_WORK_STOPPED is set before cancelling
* stats_work to prevent rescheduling during teardown
@@ -2317,7 +2307,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @drop_meter: index of the single shared zero-rate firmware meter
* used to unconditionally drop traffic (used to block
* flooding)
@@ -318,6 +327,7 @@ union mxl862xx_fw_version {
@@ -316,6 +325,7 @@ struct mxl862xx_fw_version {
* (0 .. ds->max_num_bridges).
* @evlan_ingress_size: per-port ingress Extended VLAN block size
* @evlan_egress_size: per-port egress Extended VLAN block size
@@ -2325,15 +2315,15 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @vf_block_size: per-port VLAN Filter block size
* @cpu_trap_fid: firmware bridge FID allocated for PCE-trapped frames;
* configured with uc/mc/bc flood all enabled so that
@@ -334,6 +344,7 @@ struct mxl862xx_priv {
@@ -332,6 +342,7 @@ struct mxl862xx_priv {
struct mdio_device *mdiodev;
struct work_struct crc_err_work;
unsigned long flags;
+ enum dsa_tag_protocol tag_proto;
u16 drop_meter;
union mxl862xx_fw_version fw_version;
struct mxl862xx_fw_version fw_version;
struct mxl862xx_pcs serdes_ports[8];
@@ -341,6 +352,7 @@ struct mxl862xx_priv {
@@ -340,6 +351,7 @@ struct mxl862xx_priv {
u16 bridges[MXL862XX_MAX_BRIDGES + 1];
u16 evlan_ingress_size;
u16 evlan_egress_size;
@@ -1,7 +1,7 @@
From a32f6a9c09b90e767a03ddac34d061545a0cf15e Mon Sep 17 00:00:00 2001
From 4220567bd18b2174c74e90d22f3bf47422c1fdf6 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 03:44:41 +0000
Subject: [PATCH 10/20] net: dsa: mxl862xx: add link aggregation support
Subject: [PATCH 09/19] net: dsa: mxl862xx: add link aggregation support
Implement LAG offloading via the firmware's trunking engine. A
dedicated firmware bridge port is allocated per LAG and remains
@@ -90,8 +90,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#define INT_GPHY_READ (GPY_GPY2XX_MAGIC + 0x1)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -680,7 +680,42 @@ static int mxl862xx_setup_snooping_traps
return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
@@ -695,7 +695,42 @@ static int mxl862xx_setup_snooping_traps
return mxl862xx_pce_rule_write(priv, &rule);
}
-static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
@@ -134,7 +134,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
{
struct mxl862xx_bridge_port_config br_port_cfg = {};
struct dsa_port *dp = dsa_to_port(ds, port);
@@ -713,8 +748,12 @@ static int mxl862xx_set_bridge_port(stru
@@ -728,8 +763,12 @@ static int mxl862xx_set_bridge_port(stru
dp->bridge->dev) {
if (member_dp->index == port)
continue;
@@ -149,7 +149,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
mxl862xx_cpu_bridge_port_id(ds, port));
@@ -727,7 +766,7 @@ static int mxl862xx_set_bridge_port(stru
@@ -742,7 +781,7 @@ static int mxl862xx_set_bridge_port(stru
bridge_id = dp->bridge ? priv->bridges[dp->bridge->num] : p->fid;
@@ -158,7 +158,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
br_port_cfg.bridge_id = cpu_to_le16(bridge_id);
br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_ID |
MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
@@ -808,11 +847,38 @@ static int mxl862xx_set_bridge_port(stru
@@ -823,11 +862,38 @@ static int mxl862xx_set_bridge_port(stru
br_port_cfg);
}
@@ -198,7 +198,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
dsa_switch_for_each_bridge_member(dp, ds, bridge->dev) {
err = mxl862xx_set_bridge_port(ds, dp->index);
@@ -820,6 +886,25 @@ static int mxl862xx_sync_bridge_members(
@@ -835,6 +901,25 @@ static int mxl862xx_sync_bridge_members(
ret = err;
}
@@ -224,7 +224,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return ret;
}
@@ -1859,6 +1944,408 @@ static int mxl862xx_setup_cpu_bridge(str
@@ -1875,6 +1960,408 @@ static int mxl862xx_setup_cpu_bridge(str
return mxl862xx_set_bridge_port(ds, port);
}
@@ -633,7 +633,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port,
const struct dsa_bridge bridge,
bool *tx_fwd_offload,
@@ -1884,7 +2371,18 @@ static int mxl862xx_port_bridge_join(str
@@ -1900,7 +2387,18 @@ static int mxl862xx_port_bridge_join(str
return 0;
}
@@ -653,7 +653,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port,
@@ -1935,6 +2433,17 @@ static void mxl862xx_port_bridge_leave(s
@@ -1951,6 +2449,17 @@ static void mxl862xx_port_bridge_leave(s
"failed to update CPU VBP for port %d: %pe\n", port,
ERR_PTR(err));
@@ -671,7 +671,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (!dsa_bridge_ports(ds, bridge.dev))
mxl862xx_free_bridge(ds, &bridge);
}
@@ -2593,18 +3102,17 @@ static int mxl862xx_get_fid(struct dsa_s
@@ -2609,18 +3118,17 @@ static int mxl862xx_get_fid(struct dsa_s
}
/**
@@ -697,7 +697,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
*/
static int mxl862xx_fdb_bridge_port(struct dsa_switch *ds, int port,
const struct dsa_db db)
@@ -2620,7 +3128,7 @@ static int mxl862xx_fdb_bridge_port(stru
@@ -2636,7 +3144,7 @@ static int mxl862xx_fdb_bridge_port(stru
return bp_cpu;
}
@@ -706,7 +706,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
/**
@@ -2867,11 +3375,43 @@ static int mxl862xx_port_fdb_del(struct
@@ -2883,11 +3391,43 @@ static int mxl862xx_port_fdb_del(struct
return ret;
}
@@ -750,7 +750,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
u32 entry_port_id;
int ret;
@@ -2885,7 +3425,7 @@ static int mxl862xx_port_fdb_dump(struct
@@ -2901,7 +3441,7 @@ static int mxl862xx_port_fdb_dump(struct
entry_port_id = le32_to_cpu(param.port_id);
@@ -759,7 +759,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = cb(param.mac, FIELD_GET(MXL862XX_TCI_VLAN_ID,
le16_to_cpu(param.tci)),
param.static_entry, data);
@@ -3556,6 +4096,11 @@ static const struct dsa_switch_ops mxl86
@@ -3572,6 +4112,11 @@ static const struct dsa_switch_ops mxl86
.port_fdb_dump = mxl862xx_port_fdb_dump,
.port_mdb_add = mxl862xx_port_mdb_add,
.port_mdb_del = mxl862xx_port_mdb_del,
@@ -771,7 +771,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.port_vlan_filtering = mxl862xx_port_vlan_filtering,
.port_vlan_add = mxl862xx_port_vlan_add,
.port_vlan_del = mxl862xx_port_vlan_del,
@@ -3597,6 +4142,7 @@ static int mxl862xx_probe(struct mdio_de
@@ -3612,6 +4157,7 @@ static int mxl862xx_probe(struct mdio_de
ds->num_ports = MXL862XX_MAX_PORTS;
ds->fdb_isolation = true;
ds->max_num_bridges = MXL862XX_MAX_BRIDGES;
@@ -781,7 +781,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -16,6 +16,19 @@ struct mxl862xx_priv;
@@ -19,6 +19,19 @@ struct mxl862xx_priv;
#define MXL862XX_MAX_BRIDGE_PORTS 128
#define MXL862XX_TOTAL_EVLAN_ENTRIES 1024
#define MXL862XX_TOTAL_VF_ENTRIES 1024
@@ -801,7 +801,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
/* Number of __le16 words in a firmware portmap (128-bit bitmap). */
#define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16)
@@ -227,6 +240,12 @@ struct mxl862xx_port_stats {
@@ -230,6 +243,12 @@ struct mxl862xx_port_stats {
* @stats_lock: protects accumulator reads in .get_stats64 against
* concurrent updates from the polling work
* @tag_8021q_vid: currently assigned tag_8021q management VID
@@ -814,7 +814,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
*/
struct mxl862xx_port {
struct mxl862xx_priv *priv;
@@ -246,6 +265,9 @@ struct mxl862xx_port {
@@ -249,6 +268,9 @@ struct mxl862xx_port {
struct work_struct host_flood_work;
u16 tag_8021q_vid;
struct mxl862xx_evlan_block cpu_egress_evlan;
@@ -824,7 +824,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct mxl862xx_port_stats stats;
spinlock_t stats_lock; /* protects stats accumulators */
};
@@ -336,6 +358,15 @@ union mxl862xx_fw_version {
@@ -334,6 +356,15 @@ struct mxl862xx_fw_version {
* policy. Set once in setup() and referenced by
* fill_cpu_trap_action() via bFidEnable. The PCE FID
* action field is 6 bits, so this value must be <= 63.
@@ -840,7 +840,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @stats_work: periodic work item that polls RMON hardware counters
* and accumulates them into 64-bit per-port stats
*/
@@ -355,6 +386,8 @@ struct mxl862xx_priv {
@@ -354,6 +385,8 @@ struct mxl862xx_priv {
u16 cpu_evlan_ingress_size;
u16 vf_block_size;
u16 cpu_trap_fid;
@@ -1,7 +1,7 @@
From d919c2f8da9dbd4dda57ceebb5c8b103805b58d1 Mon Sep 17 00:00:00 2001
From 8f7296099da5eaedfe5108a6fe93296bcc0c4b45 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 12:05:29 +0000
Subject: [PATCH 11/19] net: dsa: mxl862xx: add support for mirror port
Subject: [PATCH 10/19] net: dsa: mxl862xx: add support for mirror port
The MxL862xx hardware supports a single monitor port which can be
configured to mirror any other port's ingress and/or egress traffic.
@@ -40,17 +40,17 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @age_timer: Custom MAC table aging timer in seconds
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -30,6 +30,7 @@
#define MXL862XX_COMMON_PORTCFGGET (MXL862XX_COMMON_MAGIC + 0x7)
@@ -29,6 +29,7 @@
#define MXL862XX_COMMON_CFGGET (MXL862XX_COMMON_MAGIC + 0x9)
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
+#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -1100,6 +1100,8 @@ static int mxl862xx_setup(struct dsa_swi
@@ -1116,6 +1116,8 @@ static int mxl862xx_setup(struct dsa_swi
(n_user_ports + n_cpu_ports);
}
@@ -59,8 +59,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = mxl862xx_setup_drop_meter(ds);
if (ret)
return ret;
@@ -3167,6 +3169,120 @@ static int mxl862xx_fdb_del_per_fid(stru
return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYREMOVE, param);
@@ -1960,6 +1962,120 @@ static int mxl862xx_setup_cpu_bridge(str
return mxl862xx_set_bridge_port(ds, port);
}
+static int mxl862xx_port_mirror_add(struct dsa_switch *ds, int port,
@@ -178,9 +178,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+}
+
/**
* mxl862xx_mac_portmap_add - Set port bits in a MAC table entry's portmap
* @priv: driver private data
@@ -4096,6 +4212,8 @@ static const struct dsa_switch_ops mxl86
* mxl862xx_lag_master_port - Find the LAG master (lowest-numbered member)
* @ds: DSA switch
@@ -4112,6 +4228,8 @@ static const struct dsa_switch_ops mxl86
.port_fdb_dump = mxl862xx_port_fdb_dump,
.port_mdb_add = mxl862xx_port_mdb_add,
.port_mdb_del = mxl862xx_port_mdb_del,
@@ -191,7 +191,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.port_lag_change = mxl862xx_port_lag_change,
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -240,6 +240,8 @@ struct mxl862xx_port_stats {
@@ -243,6 +243,8 @@ struct mxl862xx_port_stats {
* @stats_lock: protects accumulator reads in .get_stats64 against
* concurrent updates from the polling work
* @tag_8021q_vid: currently assigned tag_8021q management VID
@@ -200,7 +200,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @lag: non-NULL when port is member of a LAG group;
* points to the DSA LAG structure
* @lag_tx_enabled: true when this port is active for TX in its LAG
@@ -265,6 +267,8 @@ struct mxl862xx_port {
@@ -268,6 +270,8 @@ struct mxl862xx_port {
struct work_struct host_flood_work;
u16 tag_8021q_vid;
struct mxl862xx_evlan_block cpu_egress_evlan;
@@ -209,7 +209,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct dsa_lag *lag;
bool lag_tx_enabled;
u8 lag_hash_bits;
@@ -367,6 +371,8 @@ union mxl862xx_fw_version {
@@ -365,6 +369,8 @@ struct mxl862xx_fw_version {
* @trunk_hash: current global hash field bitmask (6 bits,
* MXL862XX_TRUNK_HASH_*); union of all active LAGs'
* hash requirements
@@ -218,7 +218,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @stats_work: periodic work item that polls RMON hardware counters
* and accumulates them into 64-bit per-port stats
*/
@@ -388,6 +394,7 @@ struct mxl862xx_priv {
@@ -387,6 +393,7 @@ struct mxl862xx_priv {
u16 cpu_trap_fid;
u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
u8 trunk_hash;
@@ -1,7 +1,7 @@
From 64269d9d809962a0f7e68e9b618d81e561e3eb6f Mon Sep 17 00:00:00 2001
From d11e0b07317e04f347de1b5053bb6720d72fd111 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 16:30:08 +0000
Subject: [PATCH 12/19] net: dsa: wire flash_update devlink callback to drivers
Subject: [PATCH 11/19] net: dsa: wire flash_update devlink callback to drivers
Add a devlink_flash_update callback to dsa_switch_ops so that DSA
drivers can support devlink dev flash without open-coding the devlink
@@ -1,7 +1,7 @@
From fed4225f75b6fe6898e48f472cbbee0aaa046760 Mon Sep 17 00:00:00 2001
From 4dd558c7422fcd2b5c76994928fe3a65e0059fb4 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 16:30:17 +0000
Subject: [PATCH 13/19] net: dsa: mxl862xx: add SMDIO clause-22 register access
Subject: [PATCH 12/19] net: dsa: mxl862xx: add SMDIO clause-22 register access
Add mxl862xx_smdio_read() and mxl862xx_smdio_write() for clause-22
SMDIO register access. MCUboot rescue mode only exposes clause-22
@@ -1,7 +1,7 @@
From fa186b09e346e0b7f2504232731bc9e4dee0c600 Mon Sep 17 00:00:00 2001
From 099e70920b16f5da14d34bc00ac58a5ca95c1e33 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 16:30:31 +0000
Subject: [PATCH 14/19] net: dsa: mxl862xx: add devlink flash_update and
Subject: [PATCH 13/19] net: dsa: mxl862xx: add devlink flash_update and
info_get
Implement runtime firmware upgrade via "devlink dev flash" and version
@@ -35,9 +35,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
drivers/net/dsa/mxl862xx/mxl862xx-fw.c | 434 +++++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-fw.h | 15 +
drivers/net/dsa/mxl862xx/mxl862xx-host.c | 7 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 4 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 3 +
drivers/net/dsa/mxl862xx/mxl862xx.h | 2 +
7 files changed, 464 insertions(+), 1 deletion(-)
7 files changed, 463 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/dsa/mxl862xx/mxl862xx-fw.c
create mode 100644 drivers/net/dsa/mxl862xx/mxl862xx-fw.h
@@ -57,7 +57,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x1)
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x2)
#define MXL862XX_XPCS_MAGIC 0x1a00
#define MXL862XX_XPCS_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
--- /dev/null
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-fw.c
@@ -0,0 +1,434 @@
@@ -546,19 +546,18 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#include "mxl862xx-host.h"
#include "mxl862xx-phylink.h"
@@ -4233,6 +4234,9 @@ static const struct dsa_switch_ops mxl86
@@ -4248,6 +4249,8 @@ static const struct dsa_switch_ops mxl86
.get_pause_stats = mxl862xx_get_pause_stats,
.get_rmon_stats = mxl862xx_get_rmon_stats,
.get_stats64 = mxl862xx_get_stats64,
.self_test = mxl862xx_serdes_self_test,
+ .devlink_info_get = mxl862xx_devlink_info_get,
+ .devlink_flash_update = mxl862xx_devlink_flash_update,
+
};
static int mxl862xx_probe(struct mdio_device *mdiodev)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -395,6 +395,8 @@ struct mxl862xx_priv {
@@ -394,6 +394,8 @@ struct mxl862xx_priv {
u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
u8 trunk_hash;
int mirror_dest;
@@ -1,7 +1,7 @@
From 05bc981690d6ef03143a094f28714aa0171ab571 Mon Sep 17 00:00:00 2001
From d27d60f42f5188d6cfcb771d2188633f1031646f Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 1 Apr 2026 13:43:08 +0100
Subject: [PATCH 15/19] net: dsa: mxl862xx: implement port MTU configuration
Subject: [PATCH 14/19] net: dsa: mxl862xx: implement port MTU configuration
The firmware exposes a global max_packet_len register via
MXL862XX_COMMON_CFGSET. Since this is switch-wide rather than
@@ -25,7 +25,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
@@ -3727,6 +3728,53 @@ static int mxl862xx_set_ageing_time(stru
@@ -3743,6 +3744,53 @@ static int mxl862xx_set_ageing_time(stru
return ret;
}
@@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static void mxl862xx_port_stp_state_set(struct dsa_switch *ds, int port,
u8 state)
{
@@ -4202,6 +4250,8 @@ static const struct dsa_switch_ops mxl86
@@ -4218,6 +4266,8 @@ static const struct dsa_switch_ops mxl86
.port_disable = mxl862xx_port_disable,
.port_fast_age = mxl862xx_port_fast_age,
.set_ageing_time = mxl862xx_set_ageing_time,
@@ -90,7 +90,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.port_pre_bridge_flags = mxl862xx_port_pre_bridge_flags,
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -248,6 +248,8 @@ struct mxl862xx_port_stats {
@@ -251,6 +251,8 @@ struct mxl862xx_port_stats {
* @lag_hash_bits: hash field bitmask (MXL862XX_TRUNK_HASH_*) requested
* when this port joined its LAG; used to recompute the
* global trunk_hash when a LAG is destroyed
@@ -99,7 +99,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
*/
struct mxl862xx_port {
struct mxl862xx_priv *priv;
@@ -272,6 +274,7 @@ struct mxl862xx_port {
@@ -275,6 +277,7 @@ struct mxl862xx_port {
struct dsa_lag *lag;
bool lag_tx_enabled;
u8 lag_hash_bits;
@@ -1,7 +1,7 @@
From b723f7484006aadbaa51e16b870f3c98390605b1 Mon Sep 17 00:00:00 2001
From ba48edffc80f3dd676a9e8cf63aa4778a4ed0f0d Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 1 Apr 2026 13:43:12 +0100
Subject: [PATCH 16/19] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag
Subject: [PATCH 15/19] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag
Implement hairpin mode by including the port's own bridge port ID in
its forwarding portmap. When hairpin is enabled, bridged frames whose
@@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -759,6 +759,10 @@ static int __mxl862xx_set_bridge_port(st
@@ -774,6 +774,10 @@ static int __mxl862xx_set_bridge_port(st
}
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
mxl862xx_cpu_bridge_port_id(ds, port));
@@ -35,7 +35,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
} else {
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
mxl862xx_cpu_bridge_port_id(ds, port));
@@ -3895,7 +3899,7 @@ static int mxl862xx_port_pre_bridge_flag
@@ -3911,7 +3915,7 @@ static int mxl862xx_port_pre_bridge_flag
struct netlink_ext_ack *extack)
{
if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD |
@@ -44,7 +44,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return -EINVAL;
return 0;
@@ -3937,7 +3941,11 @@ static int mxl862xx_port_bridge_flags(st
@@ -3953,7 +3957,11 @@ static int mxl862xx_port_bridge_flags(st
if (flags.mask & BR_LEARNING)
priv->ports[port].learning = !!(flags.val & BR_LEARNING);
@@ -59,7 +59,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -240,6 +240,10 @@ struct mxl862xx_port_stats {
@@ -243,6 +243,10 @@ struct mxl862xx_port_stats {
* @stats_lock: protects accumulator reads in .get_stats64 against
* concurrent updates from the polling work
* @tag_8021q_vid: currently assigned tag_8021q management VID
@@ -70,7 +70,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @ingress_mirror: true when ingress mirroring is active on this port
* @egress_mirror: true when egress mirroring is active on this port
* @lag: non-NULL when port is member of a LAG group;
@@ -269,6 +273,7 @@ struct mxl862xx_port {
@@ -272,6 +276,7 @@ struct mxl862xx_port {
struct work_struct host_flood_work;
u16 tag_8021q_vid;
struct mxl862xx_evlan_block cpu_egress_evlan;
@@ -1,7 +1,7 @@
From d8f20ba50ce0f93f34a41a9b833be76a5d1d2714 Mon Sep 17 00:00:00 2001
From 45fcd9669da62b27823004480c07854c54574a1a Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 25 Mar 2026 01:51:33 +0000
Subject: [PATCH 17/19] net: dsa: mxl862xx: support BR_ISOLATED bridge flag
Subject: [PATCH 16/19] net: dsa: mxl862xx: support BR_ISOLATED bridge flag
Implement port isolation by excluding isolated ports from each other's
forwarding portmaps in sync_bridge_members. Non-isolated ports can
@@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -752,6 +752,8 @@ static int __mxl862xx_set_bridge_port(st
@@ -767,6 +767,8 @@ static int __mxl862xx_set_bridge_port(st
continue;
if (!mxl862xx_is_lag_master(priv, member_dp->index))
continue;
@@ -28,7 +28,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
mxl862xx_fw_portmap_set_bit(
br_port_cfg.bridge_port_map,
mxl862xx_lag_bridge_port(priv,
@@ -3899,7 +3901,7 @@ static int mxl862xx_port_pre_bridge_flag
@@ -3915,7 +3917,7 @@ static int mxl862xx_port_pre_bridge_flag
struct netlink_ext_ack *extack)
{
if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD |
@@ -37,7 +37,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return -EINVAL;
return 0;
@@ -3912,6 +3914,7 @@ static int mxl862xx_port_bridge_flags(st
@@ -3928,6 +3930,7 @@ static int mxl862xx_port_bridge_flags(st
struct mxl862xx_priv *priv = ds->priv;
unsigned long old_block = priv->ports[port].flood_block;
unsigned long block = old_block;
@@ -45,7 +45,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
int ret;
if (flags.mask & BR_FLOOD) {
@@ -3952,6 +3955,21 @@ static int mxl862xx_port_bridge_flags(st
@@ -3968,6 +3971,21 @@ static int mxl862xx_port_bridge_flags(st
return ret;
}
@@ -69,7 +69,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -213,6 +213,9 @@ struct mxl862xx_port_stats {
@@ -216,6 +216,9 @@ struct mxl862xx_port_stats {
* @flood_block: bitmask of firmware meter indices that are currently
* rate-limiting flood traffic on this port (zero-rate
* meters used to block flooding)
@@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @learning: true when address learning is enabled on this port
* @setup_done: set at end of port_setup, cleared at start of
* port_teardown; guards deferred work against
@@ -259,6 +262,7 @@ struct mxl862xx_port {
@@ -262,6 +265,7 @@ struct mxl862xx_port {
struct mxl862xx_priv *priv;
u16 fid;
unsigned long flood_block;
@@ -0,0 +1,134 @@
From 8120b9b88ec47ee41b8350e3e4341839f5fdc28e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:17:49 +0000
Subject: [PATCH 17/19] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE
workaround for old firmware
Re-introduce the legacy PCE rule paths needed for firmware versions
older than 1.0.83.
Firmware >= 1.0.83 exposes the new GSW_TFLOW_PCERULELOGICWRITE API
which selects the per-CTP block via @region/@logicalportid and grows
the hardware block on demand. Older firmware lacks that command and
exposes only the legacy GSW_TFLOW_PCERULEWRITE call, where the rule
index is a direct offset into a fixed-size pre-allocated CTP block.
Add MXL862XX_TFLOW_PCERULEWRITE back to mxl862xx-cmd.h and make
mxl862xx_pce_rule_write() pick the right command at runtime based on
the cached firmware version.
In addition, firmware older than 1.0.80 still installs global PCE
rules at boot that redirect link-local frames (BPDUs, LLDP, LACP) to
port 0 (the on-chip microcontroller) instead of the DSA CPU port.
With port 0 disabled under DSA these rules silently drop matching
traffic. Re-introduce mxl862xx_disable_fw_global_rules() to clear
them out during setup. The upstream submission replaced that call
with a dev_warn() since firmware >= 1.0.80 no longer installs the
problematic rules.
This commit is for downstream use only and must not be submitted
upstream.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 61 +++++++++++++++++++++----
2 files changed, 53 insertions(+), 9 deletions(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -32,6 +32,7 @@
#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
+#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
#define MXL862XX_TFLOW_PCERULEFREE (MXL862XX_TFLOW_MAGIC + 0x5)
#define MXL862XX_TFLOW_PCERULELOGICWRITE \
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -449,6 +449,43 @@ static int mxl862xx_setup_drop_meter(str
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
}
+/* Disable firmware global PCE rules that trap various protocols to the
+ * on-die microcontroller (port 0) via PORTMAP_CPU. Under DSA, these
+ * frames must either reach the host CPU via per-port rules (link-local)
+ * or through the normal bridge forwarding path (ARP broadcast), so the
+ * global firmware rules are not needed. With the microcontroller port
+ * disabled they would silently drop matching traffic.
+ *
+ * Global rules have lower indices than CTP rules, hence higher priority
+ * in the PCE pipeline -- they must be explicitly disabled or they will
+ * shadow the per-CTP traps.
+ *
+ * Indices from gsw_flow_index.h:
+ * 1 -- BPDU (STP/RSTP, dst 01:80:c2:00:00:00)
+ * 3 -- LLDP (EtherType 0x88cc)
+ * 4 -- OAM/LACP (EtherType 0x8809)
+ * 6 -- System MAC (dst 02:e0:92:00:00:01, vendor management MAC)
+ * 7 -- ARP Request (broadcast + EtherType 0x0806 + TPA 192.0.2.1)
+ */
+static int mxl862xx_disable_fw_global_rules(struct dsa_switch *ds)
+{
+ static const u16 indices[] = { 1, 3, 4, 6, 7 };
+ struct mxl862xx_pce_rule rule;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(indices); i++) {
+ memset(&rule, 0, sizeof(rule));
+ rule.pattern.index = cpu_to_le16(indices[i]);
+ /* pattern.enable == 0 -> rule is disabled */
+
+ ret = MXL862XX_API_WRITE(ds->priv,
+ MXL862XX_TFLOW_PCERULEWRITE, rule);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
/* Per-CTP logical indices for protocol trap rules.
*
@@ -463,16 +500,20 @@ static int mxl862xx_setup_drop_meter(str
#define MXL862XX_MLDV1_CTP_INDEX 3
#define MXL862XX_MLDV2_CTP_INDEX 4
-/* Install (or overwrite) a PCE rule via the firmware's logical-index
- * API. The firmware translates the logical index in @rule->pattern.index
- * to a physical position within the block selected by @rule->region and
- * @rule->logicalportid, and expands the hardware block size as needed.
+/* Install (or overwrite) a PCE rule. On firmware >= 1.0.83 use the
+ * logical-index API (PCERULELOGICWRITE), which grows the per-CTP block
+ * on demand. On older firmware that API does not exist, so fall back
+ * to the legacy PCERULEWRITE call which uses the rule index as a
+ * direct offset into a fixed-size pre-allocated CTP block.
*/
static int mxl862xx_pce_rule_write(struct mxl862xx_priv *priv,
struct mxl862xx_pce_rule *rule)
{
- return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULELOGICWRITE,
- *rule);
+ u16 cmd = MXL862XX_FW_VER_MIN(priv, 1, 0, 83) ?
+ MXL862XX_TFLOW_PCERULELOGICWRITE :
+ MXL862XX_TFLOW_PCERULEWRITE;
+
+ return MXL862XX_API_WRITE(priv, cmd, *rule);
}
/**
@@ -1130,9 +1171,11 @@ static int mxl862xx_setup(struct dsa_swi
if (ret)
return ret;
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
- dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules "
- "that interfere with DSA operation, please update\n");
+ if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80)) {
+ ret = mxl862xx_disable_fw_global_rules(ds);
+ if (ret)
+ return ret;
+ }
/* Pre-allocate firmware resources for all ports. The DSA core
* calls change_tag_protocol() between setup() and port_setup(),
@@ -0,0 +1,490 @@
From 494a1eb62219d9ccb97a60e15ea59e7de2f5d9bc Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:19:56 +0000
Subject: [PATCH 18/19] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API
fallback for old firmware
Re-introduce the SYS_MISC_SFP_SET-based PCS implementation as a
fallback for firmware versions older than 1.0.84 which lack the
XPCS API. mxl862xx_setup_pcs() selects between the XPCS ops and
legacy SFP ops based on firmware version.
This commit is for downstream use only and must not be submitted
upstream.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 244 ++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 3 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 155 ++++++++++++-
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
4 files changed, 401 insertions(+), 4 deletions(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -2164,6 +2164,18 @@ struct mxl862xx_sys_fw_image_version {
} __packed;
/**
+ * enum mxl862xx_port_duplex - Ethernet port duplex status
+ * @MXL862XX_DUPLEX_FULL: Port operates in full-duplex mode
+ * @MXL862XX_DUPLEX_HALF: Port operates in half-duplex mode
+ * @MXL862XX_DUPLEX_AUTO: Port operates in Auto mode
+ */
+enum mxl862xx_port_duplex {
+ MXL862XX_DUPLEX_FULL = 0,
+ MXL862XX_DUPLEX_HALF,
+ MXL862XX_DUPLEX_AUTO,
+};
+
+/**
* enum mxl862xx_port_type - Port Type
* @MXL862XX_LOGICAL_PORT: Logical Port
* @MXL862XX_PHYSICAL_PORT: Physical Port
@@ -2178,6 +2190,238 @@ enum mxl862xx_port_type {
};
/**
+ * enum mxl862xx_port_enable - port enable type selection.
+ * @MXL862XX_PORT_DISABLE: the port is disabled in both directions
+ * @MXL862XX_PORT_ENABLE_RXTX: the port is enabled in both directions
+ * @MXL862XX_PORT_ENABLE_RX: the port is enabled in the receive direction
+ * @MXL862XX_PORT_ENABLE_TX: the port is enabled in the transmit direction
+ */
+enum mxl862xx_port_enable {
+ MXL862XX_PORT_DISABLE = 0,
+ MXL862XX_PORT_ENABLE_RXTX,
+ MXL862XX_PORT_ENABLE_RX,
+ MXL862XX_PORT_ENABLE_TX,
+};
+
+/**
+ * enum mxl862xx_port_flow - ethernet flow control status
+ * @MXL862XX_FLOW_AUTO: automatic flow control
+ * @MXL862XX_FLOW_RX: receive flow control only
+ * @MXL862XX_FLOW_TX: transmit flow control only
+ * @MXL862XX_FLOW_RXTX: receive and transmit flow control
+ * @MXL862XX_FLOW_OFF: no flow control
+ */
+enum mxl862xx_port_flow {
+ MXL862XX_FLOW_AUTO = 0,
+ MXL862XX_FLOW_RX,
+ MXL862XX_FLOW_TX,
+ MXL862XX_FLOW_RXTX,
+ MXL862XX_FLOW_OFF,
+};
+
+/**
+ * enum mxl862xx_port_monitor - port mirror options
+ * @MXL862XX_PORT_MONITOR_NONE: mirroring is disabled
+ * @MXL862XX_PORT_MONITOR_RX: ingress packets are mirrored
+ * @MXL862XX_PORT_MONITOR_TX: egress packets are mirrored
+ * @MXL862XX_PORT_MONITOR_RXTX: ingress and egress packets are mirrored
+ * @MXL862XX_PORT_MONITOR_VLAN_UNKNOWN: mirroring of 'unknown VLAN violation' frames
+ * @MXL862XX_PORT_MONITOR_VLAN_MEMBERSHIP: mirroring of 'VLAN ingress or egress membership
+ * violation' frames
+ * @MXL862XX_PORT_MONITOR_PORT_STATE: mirroring of 'port state violation' frames
+ * @MXL862XX_PORT_MONITOR_LEARNING_LIMIT: mirroring of 'MAC learning limit violation' frames
+ * @MXL862XX_PORT_MONITOR_PORT_LOCK: mirroring of 'port lock violation' frames
+ */
+enum mxl862xx_port_monitor {
+ MXL862XX_PORT_MONITOR_NONE = 0,
+ MXL862XX_PORT_MONITOR_RX,
+ MXL862XX_PORT_MONITOR_TX,
+ MXL862XX_PORT_MONITOR_RXTX,
+ MXL862XX_PORT_MONITOR_VLAN_UNKNOWN,
+ MXL862XX_PORT_MONITOR_VLAN_MEMBERSHIP = 16,
+ MXL862XX_PORT_MONITOR_PORT_STATE = 32,
+ MXL862XX_PORT_MONITOR_LEARNING_LIMIT = 64,
+ MXL862XX_PORT_MONITOR_PORT_LOCK = 128,
+};
+
+/**
+ * enum mxl862xx_if_rmon_mode - interface RMON counter mode
+ * @MXL862XX_IF_RMON_FID: FID based RMON counters
+ * @MXL862XX_IF_RMON_SUBID: sub-interface ID based
+ * @MXL862XX_IF_RMON_FLOWID_LSB: flow ID based (bits 3:0)
+ * @MXL862XX_IF_RMON_FLOWID_MSB: flow ID based (bits 7:4)
+ */
+enum mxl862xx_if_rmon_mode {
+ MXL862XX_IF_RMON_FID = 0,
+ MXL862XX_IF_RMON_SUBID,
+ MXL862XX_IF_RMON_FLOWID_LSB,
+ MXL862XX_IF_RMON_FLOWID_MSB,
+};
+
+/**
+ * struct mxl862xx_port_cfg - Port Configuration Parameters
+ * @port_type: See &enum mxl862xx_port_type
+ * @port_id: Ethernet Port number (zero-based counting)
+ * @enable: See &enum mxl862xx_port_enable
+ * @unicast_unknown_drop: Drop unknown unicast packets
+ * @multicast_unknown_drop: Drop unknown multicast packets
+ * @reserved_packet_drop: Drop reserved packet types
+ * @broadcast_drop: Drop broadcast packets
+ * @aging: Enables MAC address table aging.
+ * @learning: MAC address table learning
+ * @learning_mac_port_lock: Automatic MAC address table learning locking on the port
+ * @learning_limit: Automatic MAC address table learning limitation on this port
+ * @mac_spoofing_detection: MAC spoofing detection. Identifies ingress packets that carry
+ * a MAC source address which was previously learned on a different ingress port
+ * @flow_ctrl: See &enum mxl862xx_port_flow
+ * @port_monitor: See &enum mxl862xx_port_monitor
+ * @if_counters: Assign Interface RMON Counters for this Port
+ * @if_count_start_idx: Interface RMON Counters Start Index
+ * @if_rmonmode: See &enum mxl862xx_if_rmon_mode
+ */
+struct mxl862xx_port_cfg {
+ __le32 port_type; /* enum mxl862xx_port_type */
+ __le16 port_id;
+ __le32 enable; /* enum mxl862xx_port_enable */
+ u8 unicast_unknown_drop;
+ u8 multicast_unknown_drop;
+ u8 reserved_packet_drop;
+ u8 broadcast_drop;
+ u8 aging;
+ u8 learning;
+ u8 learning_mac_port_lock;
+ __le16 learning_limit;
+ u8 mac_spoofing_detection;
+ __le32 flow_ctrl; /* enum mxl862xx_port_flow */
+ __le32 port_monitor; /* enum mxl862xx_port_monitor */
+ u8 if_counters;
+ __le32 if_count_start_idx;
+ __le32 if_rmonmode; /* enum mxl862xx_if_rmon_mode */
+} __packed;
+
+/**
+ * enum mxl862xx_port_speed - Ethernet port speed mode
+ * @MXL862XX_PORT_SPEED_10: 10 Mbit/s
+ * @MXL862XX_PORT_SPEED_100: 100 Mbit/s
+ * @MXL862XX_PORT_SPEED_200: 200 Mbit/s
+ * @MXL862XX_PORT_SPEED_1000: 1000 Mbit/s
+ * @MXL862XX_PORT_SPEED_2500: 2.5 Gbit/s
+ * @MXL862XX_PORT_SPEED_5000: 5 Gbit/s
+ * @MXL862XX_PORT_SPEED_10000: 10 Gbit/s
+ * @MXL862XX_PORT_SPEED_AUTO: Auto speed for XGMAC
+ */
+enum mxl862xx_port_speed {
+ MXL862XX_PORT_SPEED_10 = 0,
+ MXL862XX_PORT_SPEED_100,
+ MXL862XX_PORT_SPEED_200,
+ MXL862XX_PORT_SPEED_1000,
+ MXL862XX_PORT_SPEED_2500,
+ MXL862XX_PORT_SPEED_5000,
+ MXL862XX_PORT_SPEED_10000,
+ MXL862XX_PORT_SPEED_AUTO,
+};
+
+/**
+ * enum mxl862xx_port_link - Force the MAC and PHY link modus
+ * @MXL862XX_PORT_LINK_UP: Link up
+ * @MXL862XX_PORT_LINK_DOWN: Link down
+ * @MXL862XX_PORT_LINK_AUTO: Link Auto
+ */
+enum mxl862xx_port_link {
+ MXL862XX_PORT_LINK_UP = 0,
+ MXL862XX_PORT_LINK_DOWN,
+ MXL862XX_PORT_LINK_AUTO,
+};
+
+/**
+ * enum mxl862xx_mii_mode - Ethernet port interface mode
+ * @MXL862XX_PORT_HW_MII: Normal PHY interface
+ * @MXL862XX_PORT_HW_RMII: Reduced MII interface in normal mode
+ * @MXL862XX_PORT_HW_GMII: GMII or MII, depending upon the speed
+ * @MXL862XX_PORT_HW_RGMII: RGMII mode
+ * @MXL862XX_PORT_HW_XGMII: XGMII mode
+ */
+enum mxl862xx_mii_mode {
+ MXL862XX_PORT_HW_MII = 0,
+ MXL862XX_PORT_HW_RMII,
+ MXL862XX_PORT_HW_GMII,
+ MXL862XX_PORT_HW_RGMII,
+ MXL862XX_PORT_HW_XGMII,
+};
+
+/**
+ * enum mxl862xx_mii_type - Ethernet port configuration for PHY or MAC mode
+ * @MXL862XX_PORT_MAC: The Ethernet port is configured to work in MAC mode
+ * @MXL862XX_PORT_PHY: The Ethernet port is configured to work in PHY mode
+ */
+enum mxl862xx_mii_type {
+ MXL862XX_PORT_MAC = 0,
+ MXL862XX_PORT_PHY,
+};
+
+/**
+ * enum mxl862xx_clk_mode - Ethernet port clock source configuration
+ * @MXL862XX_PORT_CLK_NA: Clock Mode not applicable
+ * @MXL862XX_PORT_CLK_MASTER: Clock Master Mode.
+ * @MXL862XX_PORT_CLK_SLAVE: Clock Slave Mode.
+ */
+enum mxl862xx_clk_mode {
+ MXL862XX_PORT_CLK_NA = 0,
+ MXL862XX_PORT_CLK_MASTER,
+ MXL862XX_PORT_CLK_SLAVE,
+};
+
+/**
+ * struct mxl862xx_port_link_cfg - Ethernet port link, speed status and flow control status
+ * @port_id: Ethernet Port number
+ * @duplex_force: Force Port Duplex Mode
+ * @duplex: See &enum mxl862xx_port_duplex
+ * @speed_force: Force Link Speed
+ * @speed: See &enum mxl862xx_port_speed
+ * @link_force: Force Link
+ * @link: See &enum mxl862xx_port_link
+ * @mii_mode: See &enum mxl862xx_mii_mode
+ * @mii_type: See &enum mxl862xx_mii_type
+ * @clk_mode: See &enum mxl862xx_clk_mode
+ * @lpi: 'Low Power Idle' Support for 'Energy Efficient Ethernet'
+ */
+struct mxl862xx_port_link_cfg {
+ __le16 port_id;
+ u8 duplex_force;
+ __le32 duplex; /* enum mxl862xx_port_duplex */
+ u8 speed_force;
+ __le32 speed; /* enum mxl862xx_port_speed */
+ u8 link_force;
+ __le32 link; /* enum mxl862xx_port_link */
+ __le32 mii_mode; /* enum mxl862xx_mii_mode */
+ __le32 mii_type; /* enum mxl862xx_mii_type */
+ __le32 clk_mode; /* enum mxl862xx_clk_mode */
+ u8 lpi;
+} __packed;
+
+/**
+ * struct mxl862xx_sys_sfp_cfg - legacy SFP/SerDes port configuration
+ * @port_id: port id (0 or 1)
+ * @option: config options (0 - SFP mode/speed/link-status, 1 - flow control)
+ * @mode: SFP mode (0 - auto, 1 - fix, 2 - disable)
+ * @speed: select speed when mode is 1
+ * @link: get link state
+ * @fc_en: flow control (0 - disable, 1 - enable)
+ */
+struct mxl862xx_sys_sfp_cfg {
+ u8 port_id:4;
+ u8 option:4;
+ union {
+ struct {
+ u8 mode;
+ u8 speed;
+ u8 link;
+ };
+ u8 fc_en;
+ };
+} __packed;
+
+/**
* enum mxl862xx_rmon_port_type - RMON counter table type
* @MXL862XX_RMON_CTP_PORT_RX: CTP RX counters
* @MXL862XX_RMON_CTP_PORT_TX: CTP TX counters
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -27,6 +27,8 @@
#define SYS_MISC_MAGIC 0x1900
#define MXL862XX_XPCS_MAGIC 0x1a00
+#define MXL862XX_COMMON_PORTLINKCFGGET (MXL862XX_COMMON_MAGIC + 0x5)
+#define MXL862XX_COMMON_PORTCFGGET (MXL862XX_COMMON_MAGIC + 0x7)
#define MXL862XX_COMMON_CFGGET (MXL862XX_COMMON_MAGIC + 0x9)
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
@@ -86,6 +88,7 @@
#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x1)
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x2)
+#define SYS_MISC_SFP_SET (SYS_MISC_MAGIC + 0xe)
#define MXL862XX_XPCS_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
#define MXL862XX_XPCS_PCS_GET_STATE (MXL862XX_XPCS_MAGIC + 0x2)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
@@ -62,6 +62,152 @@ static struct mxl862xx_pcs *pcs_to_mxl86
return container_of(pcs, struct mxl862xx_pcs, pcs);
}
+/* Legacy SFP-based PCS implementation for firmware < 1.0.84 */
+static int mxl862xx_legacy_pcs_config(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct mxl862xx_pcs *mpcs = pcs_to_mxl862xx_pcs(pcs);
+ struct mxl862xx_priv *priv = mpcs->priv;
+ struct mxl862xx_sys_sfp_cfg ser_intf = {
+ .option = 0,
+ .mode = 1,
+ };
+
+ if (mpcs->slot != 0)
+ return 0;
+
+ ser_intf.port_id = mpcs->serdes_id;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ ser_intf.speed = 8;
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ ser_intf.speed = (neg_mode & PHYLINK_PCS_NEG_INBAND) ? 1 : 7;
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ ser_intf.speed = 4;
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ ser_intf.speed = 2;
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ ser_intf.speed = 3;
+ break;
+ default:
+ dev_err(priv->ds->dev, "unsupported interface: %s\n",
+ phy_modes(interface));
+ return -EINVAL;
+ }
+
+ return MXL862XX_API_WRITE(priv, SYS_MISC_SFP_SET, ser_intf);
+}
+
+static void mxl862xx_legacy_pcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
+{
+ struct mxl862xx_pcs *mpcs = pcs_to_mxl862xx_pcs(pcs);
+ struct mxl862xx_priv *priv = mpcs->priv;
+ struct mxl862xx_port_link_cfg port_link_cfg = {
+ .port_id = cpu_to_le16(MXL862XX_PCS_PORT(mpcs)),
+ };
+ struct mxl862xx_port_cfg port_cfg = {
+ .port_id = cpu_to_le16(MXL862XX_PCS_PORT(mpcs)),
+ };
+ int ret;
+
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTLINKCFGGET,
+ port_link_cfg);
+ if (ret)
+ return;
+
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTCFGGET, port_cfg);
+ if (ret)
+ return;
+
+ state->link = (le32_to_cpu(port_link_cfg.link) == MXL862XX_PORT_LINK_UP);
+ state->an_complete = state->link;
+
+ switch (le32_to_cpu(port_link_cfg.speed)) {
+ case MXL862XX_PORT_SPEED_10:
+ state->speed = SPEED_10;
+ break;
+ case MXL862XX_PORT_SPEED_100:
+ state->speed = SPEED_100;
+ break;
+ case MXL862XX_PORT_SPEED_1000:
+ state->speed = SPEED_1000;
+ break;
+ case MXL862XX_PORT_SPEED_2500:
+ state->speed = SPEED_2500;
+ break;
+ case MXL862XX_PORT_SPEED_5000:
+ state->speed = SPEED_5000;
+ break;
+ case MXL862XX_PORT_SPEED_10000:
+ state->speed = SPEED_10000;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ break;
+ }
+
+ switch (le32_to_cpu(port_link_cfg.duplex)) {
+ case MXL862XX_DUPLEX_HALF:
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MXL862XX_DUPLEX_FULL:
+ state->duplex = DUPLEX_FULL;
+ break;
+ default:
+ state->duplex = DUPLEX_UNKNOWN;
+ break;
+ }
+
+ state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
+ switch (le32_to_cpu(port_cfg.flow_ctrl)) {
+ case MXL862XX_FLOW_RXTX:
+ state->pause |= MLO_PAUSE_TXRX_MASK;
+ break;
+ case MXL862XX_FLOW_TX:
+ state->pause |= MLO_PAUSE_TX;
+ break;
+ case MXL862XX_FLOW_RX:
+ state->pause |= MLO_PAUSE_RX;
+ break;
+ case MXL862XX_FLOW_OFF:
+ default:
+ break;
+ }
+}
+
+static unsigned int
+mxl862xx_legacy_pcs_inband_caps(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ return LINK_INBAND_DISABLE;
+ default:
+ return 0;
+ }
+}
+
+static const struct phylink_pcs_ops mxl862xx_legacy_pcs_ops = {
+ .pcs_get_state = mxl862xx_legacy_pcs_get_state,
+ .pcs_config = mxl862xx_legacy_pcs_config,
+ .pcs_inband_caps = mxl862xx_legacy_pcs_inband_caps,
+};
+
static int mxl862xx_xpcs_if_mode(phy_interface_t interface)
{
switch (interface) {
@@ -351,7 +497,10 @@ void mxl862xx_setup_pcs(struct mxl862xx_
pcs->slot = MXL862XX_SERDES_SLOT(port);
pcs->interface = PHY_INTERFACE_MODE_NA;
- pcs->pcs.ops = &mxl862xx_pcs_ops;
+ if (MXL862XX_FW_VER_MIN(priv, 1, 0, 84))
+ pcs->pcs.ops = &mxl862xx_pcs_ops;
+ else
+ pcs->pcs.ops = &mxl862xx_legacy_pcs_ops;
pcs->pcs.poll = true;
}
@@ -363,9 +512,6 @@ mxl862xx_phylink_mac_select_pcs(struct p
struct mxl862xx_priv *priv = dp->ds->priv;
int port = dp->index;
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 84))
- return NULL;
-
switch (port) {
case 9 ... 16:
return &priv->serdes_ports[port - 9].pcs;
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
@@ -11,6 +11,9 @@
(((port) - MXL862XX_FIRST_SERDES_PORT) % MXL862XX_SERDES_SLOTS)
#define MXL862XX_SERDES_PORT_ID(port) \
(((port) - MXL862XX_FIRST_SERDES_PORT) / MXL862XX_SERDES_SLOTS)
+#define MXL862XX_PCS_PORT(mpcs) \
+ (MXL862XX_FIRST_SERDES_PORT + \
+ (mpcs)->serdes_id * MXL862XX_SERDES_SLOTS + (mpcs)->slot)
extern const struct phylink_mac_ops mxl862xx_phylink_mac_ops;
void mxl862xx_phylink_get_caps(struct dsa_switch *ds, int port,
@@ -1,81 +0,0 @@
From 8856f7610167a3005ecef401c8528111d153b554 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:17:49 +0000
Subject: [PATCH 18/19] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE
workaround for old firmware
Re-introduce the mxl862xx_disable_fw_global_rules() function that
disables firmware default global PCE rules for firmware versions
older than 1.0.80. The upstream submission replaced this with a
dev_warn() since firmware >= 1.0.80 no longer installs these rules,
but downstream deployments may still run older firmware.
This commit is for downstream use only and must not be submitted
upstream.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx.c | 45 +++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 3 deletions(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -449,6 +449,43 @@ static int mxl862xx_setup_drop_meter(str
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
}
+/* Disable firmware global PCE rules that trap various protocols to the
+ * on-die microcontroller (port 0) via PORTMAP_CPU. Under DSA, these
+ * frames must either reach the host CPU via per-port rules (link-local)
+ * or through the normal bridge forwarding path (ARP broadcast), so the
+ * global firmware rules are not needed. With the microcontroller port
+ * disabled they would silently drop matching traffic.
+ *
+ * Global rules have lower indices than CTP rules, hence higher priority
+ * in the PCE pipeline -- they must be explicitly disabled or they will
+ * shadow the per-CTP traps.
+ *
+ * Indices from gsw_flow_index.h:
+ * 1 -- BPDU (STP/RSTP, dst 01:80:c2:00:00:00)
+ * 3 -- LLDP (EtherType 0x88cc)
+ * 4 -- OAM/LACP (EtherType 0x8809)
+ * 6 -- System MAC (dst 02:e0:92:00:00:01, vendor management MAC)
+ * 7 -- ARP Request (broadcast + EtherType 0x0806 + TPA 192.0.2.1)
+ */
+static int mxl862xx_disable_fw_global_rules(struct dsa_switch *ds)
+{
+ static const u16 indices[] = { 1, 3, 4, 6, 7 };
+ struct mxl862xx_pce_rule rule;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(indices); i++) {
+ memset(&rule, 0, sizeof(rule));
+ rule.pattern.index = cpu_to_le16(indices[i]);
+ /* pattern.enable == 0 -> rule is disabled */
+
+ ret = MXL862XX_API_WRITE(ds->priv,
+ MXL862XX_TFLOW_PCERULEWRITE, rule);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
/* Per-CTP offsets for protocol trap rules. Each port's CTP flow-table
* block is pre-allocated by the firmware during init (44 entries per
@@ -1114,9 +1151,11 @@ static int mxl862xx_setup(struct dsa_swi
if (ret)
return ret;
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
- dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules "
- "that interfere with DSA operation, please update\n");
+ if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80)) {
+ ret = mxl862xx_disable_fw_global_rules(ds);
+ if (ret)
+ return ret;
+ }
/* Pre-allocate firmware resources for all ports. The DSA core
* calls change_tag_protocol() between setup() and port_setup(),
@@ -1,7 +1,7 @@
From df0c747216063041ba0d786b01f9b1e2aba5316a Mon Sep 17 00:00:00 2001
From 332dd61f50b096256f889ecb4d730d385e58aec2 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 22 Apr 2026 15:15:52 +0100
Subject: [PATCH] DO NOT SUBMIT: net: dsa: mxl862xx: increase CMD timeout
Subject: [PATCH 19/19] DO NOT SUBMIT: net: dsa: mxl862xx: increase CMD timeout
Lift the command timeout by 10x from 500ms to 5s.
This is done because older firmware can be extremely slow to respond
@@ -1,251 +0,0 @@
From f0548f842b9ff31f19452a2fc72a16f937d86008 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:19:56 +0000
Subject: [PATCH 26/26] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API
fallback for old firmware
Re-introduce the SYS_MISC_SFP_SET-based PCS implementation as a
fallback for firmware versions older than 1.0.80 which lack the
XPCS API. mxl862xx_setup_pcs() selects between the XPCS ops and
legacy SFP ops based on firmware version.
This commit is for downstream use only and must not be submitted
upstream.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 22 +++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 160 +++++++++++++++++++-
3 files changed, 178 insertions(+), 5 deletions(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -2400,6 +2400,28 @@ struct mxl862xx_sys_fw_image_version {
} __packed;
/**
+ * struct mxl862xx_sys_sfp_cfg - legacy SFP/SerDes port configuration
+ * @port_id: port id (0 or 1)
+ * @option: config options (0 - SFP mode/speed/link-status, 1 - flow control)
+ * @mode: SFP mode (0 - auto, 1 - fix, 2 - disable)
+ * @speed: select speed when mode is 1
+ * @link: get link state
+ * @fc_en: flow control (0 - disable, 1 - enable)
+ */
+struct mxl862xx_sys_sfp_cfg {
+ u8 port_id:4;
+ u8 option:4;
+ union {
+ struct {
+ u8 mode;
+ u8 speed;
+ u8 link;
+ };
+ u8 fc_en;
+ };
+} __packed;
+
+/**
* enum mxl862xx_rmon_port_type - RMON counter table type
* @MXL862XX_RMON_CTP_PORT_RX: CTP RX counters
* @MXL862XX_RMON_CTP_PORT_TX: CTP TX counters
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -85,6 +85,7 @@
#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x1)
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x2)
+#define SYS_MISC_SFP_SET (SYS_MISC_MAGIC + 0xe)
#define MXL862XX_XPCS_MAGIC 0x1a00
#define MXL862XX_XPCS_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
@@ -52,6 +52,155 @@ static struct mxl862xx_pcs *pcs_to_mxl86
return container_of(pcs, struct mxl862xx_pcs, pcs);
}
+/* Legacy SFP-based PCS implementation for firmware < 1.0.80 */
+static int mxl862xx_legacy_pcs_config(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct mxl862xx_priv *priv = pcs_to_mxl862xx_pcs(pcs)->priv;
+ int port = pcs_to_mxl862xx_pcs(pcs)->port;
+ struct mxl862xx_sys_sfp_cfg ser_intf = {
+ .option = 0,
+ .mode = 1,
+ };
+
+ if (port != 9 && port != 13)
+ return 0;
+
+ if (port == 9)
+ ser_intf.port_id = 0;
+ else
+ ser_intf.port_id = 1;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ ser_intf.speed = 8;
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ ser_intf.speed = (neg_mode & PHYLINK_PCS_NEG_INBAND) ? 1 : 7;
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ ser_intf.speed = 4;
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ ser_intf.speed = 2;
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ ser_intf.speed = 3;
+ break;
+ default:
+ dev_err(priv->ds->dev, "unsupported interface: %s\n",
+ phy_modes(interface));
+ return -EINVAL;
+ }
+
+ return MXL862XX_API_WRITE(priv, SYS_MISC_SFP_SET, ser_intf);
+}
+
+static void mxl862xx_legacy_pcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
+{
+ struct mxl862xx_priv *priv = pcs_to_mxl862xx_pcs(pcs)->priv;
+ int port = pcs_to_mxl862xx_pcs(pcs)->port;
+ struct mxl862xx_port_link_cfg port_link_cfg = {
+ .port_id = port,
+ };
+ struct mxl862xx_port_cfg port_cfg = {
+ .port_id = port,
+ };
+ int ret;
+
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTLINKCFGGET,
+ port_link_cfg);
+ if (ret)
+ return;
+
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTCFGGET, port_cfg);
+ if (ret)
+ return;
+
+ state->link = (port_link_cfg.link == MXL862XX_PORT_LINK_UP);
+ state->an_complete = state->link;
+
+ switch (port_link_cfg.speed) {
+ case MXL862XX_PORT_SPEED_10:
+ state->speed = SPEED_10;
+ break;
+ case MXL862XX_PORT_SPEED_100:
+ state->speed = SPEED_100;
+ break;
+ case MXL862XX_PORT_SPEED_1000:
+ state->speed = SPEED_1000;
+ break;
+ case MXL862XX_PORT_SPEED_2500:
+ state->speed = SPEED_2500;
+ break;
+ case MXL862XX_PORT_SPEED_5000:
+ state->speed = SPEED_5000;
+ break;
+ case MXL862XX_PORT_SPEED_10000:
+ state->speed = SPEED_10000;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ break;
+ }
+
+ switch (port_link_cfg.duplex) {
+ case MXL862XX_DUPLEX_HALF:
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MXL862XX_DUPLEX_FULL:
+ state->duplex = DUPLEX_FULL;
+ break;
+ default:
+ state->duplex = DUPLEX_UNKNOWN;
+ break;
+ }
+
+ state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
+ switch (port_cfg.flow_ctrl) {
+ case MXL862XX_FLOW_RXTX:
+ state->pause |= MLO_PAUSE_TXRX_MASK;
+ break;
+ case MXL862XX_FLOW_TX:
+ state->pause |= MLO_PAUSE_TX;
+ break;
+ case MXL862XX_FLOW_RX:
+ state->pause |= MLO_PAUSE_RX;
+ break;
+ case MXL862XX_FLOW_OFF:
+ default:
+ break;
+ }
+}
+
+static unsigned int
+mxl862xx_legacy_pcs_inband_caps(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ return LINK_INBAND_DISABLE;
+ default:
+ return 0;
+ }
+}
+
+static const struct phylink_pcs_ops mxl862xx_legacy_pcs_ops = {
+ .pcs_get_state = mxl862xx_legacy_pcs_get_state,
+ .pcs_config = mxl862xx_legacy_pcs_config,
+ .pcs_inband_caps = mxl862xx_legacy_pcs_inband_caps,
+};
+
static int mxl862xx_xpcs_port_id(int port)
{
return port >= 13;
@@ -389,7 +538,10 @@ void mxl862xx_setup_pcs(struct mxl862xx_
pcs->priv = priv;
pcs->port = port;
- pcs->pcs.ops = &mxl862xx_pcs_ops;
+ if (MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
+ pcs->pcs.ops = &mxl862xx_pcs_ops;
+ else
+ pcs->pcs.ops = &mxl862xx_legacy_pcs_ops;
pcs->pcs.poll = true;
}
@@ -401,9 +553,6 @@ mxl862xx_phylink_mac_select_pcs(struct p
struct mxl862xx_priv *priv = dp->ds->priv;
int port = dp->index;
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
- return NULL;
-
switch (port) {
case 9 ... 16:
return &priv->serdes_ports[port - 9].pcs;
@@ -534,7 +683,7 @@ void mxl862xx_serdes_get_stats(struct ds
}
void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
- struct ethtool_test *etest, u64 *data)
+ struct ethtool_test *etest, u64 *data)
{
struct mxl862xx_xpcs_prbs_cfg prbs = {};
struct mxl862xx_xpcs_bert_cfg bert = {};
@@ -1,4 +1,4 @@
From 60a23e663e0c607ae4ed871aaa24d257051ad557 Mon Sep 17 00:00:00 2001
From 1ad83956d550a252fffc473a191dbe155c4a383e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 17:56:35 +0000
Subject: [PATCH 01/19] net: dsa: mxl862xx: store firmware version for feature
@@ -8,15 +8,15 @@ Query the firmware version at init (already done in wait_ready),
cache it in priv->fw_version, and provide MXL862XX_FW_VER_MIN()
for version-gated code paths throughout the driver.
The union mxl862xx_fw_version lays out major/minor/revision so
that the u32 raw field compares with natural version ordering on
both big- and little-endian machines.
MXL862XX_FW_VER() packs major/minor/revision into a u32 with
bitwise shifts so that versions compare with natural ordering,
independent of host endianness.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx.c | 3 +++
drivers/net/dsa/mxl862xx/mxl862xx.h | 36 +++++++++++++++++++++++++++++
2 files changed, 39 insertions(+)
drivers/net/dsa/mxl862xx/mxl862xx.h | 23 +++++++++++++++++++++++
2 files changed, 26 insertions(+)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -40,46 +40,33 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#include <linux/mdio.h>
#include <linux/workqueue.h>
#include <net/dsa.h>
@@ -241,6 +242,38 @@ struct mxl862xx_port {
@@ -241,6 +242,25 @@ struct mxl862xx_port {
spinlock_t stats_lock; /* protects stats accumulators */
};
+/**
+ * union mxl862xx_fw_version - firmware version for comparison and display
+ * struct mxl862xx_fw_version - firmware version for comparison and display
+ * @major: firmware major version
+ * @minor: firmware minor version
+ * @revision: firmware revision number
+ * @raw: combined u32 for direct >= comparison (major most significant)
+ *
+ * The struct layout places major in the most-significant byte of the
+ * u32 on both big- and little-endian machines, so raw values compare
+ * with the natural major > minor > revision ordering.
+ */
+union mxl862xx_fw_version {
+ struct {
+#if defined(__BIG_ENDIAN)
+ u8 major;
+ u8 minor;
+ u16 revision;
+#elif defined(__LITTLE_ENDIAN)
+ u16 revision;
+ u8 minor;
+ u8 major;
+#endif
+ };
+ u32 raw;
+struct mxl862xx_fw_version {
+ u8 major;
+ u8 minor;
+ u16 revision;
+};
+
+#define MXL862XX_FW_VER(maj, min, rev) \
+ ((union mxl862xx_fw_version){ .major = (maj), .minor = (min), \
+ .revision = (rev) }).raw
+ (((u32)(maj) << 24) | ((u32)(min) << 16) | (rev))
+#define MXL862XX_FW_VER_MIN(priv, maj, min, rev) \
+ ((priv)->fw_version.raw >= MXL862XX_FW_VER(maj, min, rev))
+ (MXL862XX_FW_VER((priv)->fw_version.major, (priv)->fw_version.minor, \
+ (priv)->fw_version.revision) >= \
+ MXL862XX_FW_VER(maj, min, rev))
+
/* Bit indices for struct mxl862xx_priv::flags */
#define MXL862XX_FLAG_CRC_ERR 0
#define MXL862XX_FLAG_WORK_STOPPED 1
@@ -258,6 +291,8 @@ struct mxl862xx_port {
@@ -258,6 +278,8 @@ struct mxl862xx_port {
* @drop_meter: index of the single shared zero-rate firmware meter
* used to unconditionally drop traffic (used to block
* flooding)
@@ -88,11 +75,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @ports: per-port state, indexed by switch port number
* @bridges: maps DSA bridge number to firmware bridge ID;
* zero means no firmware bridge allocated for that
@@ -275,6 +310,7 @@ struct mxl862xx_priv {
@@ -275,6 +297,7 @@ struct mxl862xx_priv {
struct work_struct crc_err_work;
unsigned long flags;
u16 drop_meter;
+ union mxl862xx_fw_version fw_version;
+ struct mxl862xx_fw_version fw_version;
struct mxl862xx_port ports[MXL862XX_MAX_PORTS];
u16 bridges[MXL862XX_MAX_BRIDGES + 1];
u16 evlan_ingress_size;
@@ -1,4 +1,4 @@
From cefa0447dc95a4ddd5093f7b8cf35e654870283f Mon Sep 17 00:00:00 2001
From eaf472bfc89692cd3cc5e0298c90791f4c1c3244 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 25 Mar 2026 21:39:30 +0000
Subject: [PATCH 02/19] net: dsa: mxl862xx: move phylink stubs to
@@ -1,4 +1,4 @@
From 3c1d77006daca1df20d612850535bc6050e266ee Mon Sep 17 00:00:00 2001
From 483be884b2fdee28ac70458067c45a1369939144 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 26 Mar 2026 01:50:00 +0000
Subject: [PATCH 03/19] net: dsa: mxl862xx: move API macros to mxl862xx-host.h
@@ -1,32 +1,54 @@
From 3659914c43a587a1ca6418867834831aa518ac35 Mon Sep 17 00:00:00 2001
From 74044a2d2e62fcc3ee2b6cf22742fa94609c529e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:14:33 +0000
Subject: [PATCH 05/19] net: dsa: mxl862xx: add SerDes ethtool statistics
Expose SerDes equalization and signal detect parameters as ethtool
statistics on ports 9-16 (XPCS-backed ports). Uses the XPCS EQ_GET
and SIGNAL_DETECT firmware commands to read TX/RX equalization
coefficients, DFE taps, and link-level signal status.
Expose SerDes equalization parameters as ethtool statistics on
ports 9-16 (XPCS-backed ports). Uses the XPCS EQ_GET firmware
command to read TX/RX equalization coefficients and DFE taps.
The 19 additional stats (serdes_tx_*, serdes_rx_*, serdes_pma_link,
serdes_link_fault, serdes_in_reset) are appended after the standard
RMON counters and gated on firmware >= 1.0.80.
The 15 additional stats (serdes_tx_*, serdes_rx_*) are appended
after the standard RMON counters and gated on firmware >= 1.0.84.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 88 +++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 93 +++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 92 +++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 97 +++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 6 +-
5 files changed, 191 insertions(+), 1 deletion(-)
5 files changed, 198 insertions(+), 1 deletion(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -1812,4 +1812,92 @@ struct mxl862xx_xpcs_reset_cfg {
@@ -1668,4 +1668,96 @@ struct mxl862xx_xpcs_pcs_link_up {
__le16 result;
} __packed;
+/**
+ * struct mxl862xx_xpcs_loopback_cfg - loopback control
+ * @port_id: XPCS port index
+ * @mode: loopback mode. See &enum mxl862xx_xpcs_loopback_mode
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_loopback_cfg {
+ u8 port_id;
+ u8 mode; /* enum mxl862xx_xpcs_loopback_mode */
+ __le16 result;
+} __packed;
+
+/**
+ * struct mxl862xx_xpcs_reset_cfg - XPCS reset
+ * @port_id: XPCS port index
+ * @reset_type: reset type. See &enum mxl862xx_xpcs_reset_type
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_reset_cfg {
+ u8 port_id;
+ u8 reset_type; /* enum mxl862xx_xpcs_reset_type */
+ __le16 result;
+} __packed;
+
+/**
+ * struct mxl862xx_xpcs_eq_item - single equalization parameter
+ * @value: current initial value
@@ -94,42 +116,21 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ struct mxl862xx_xpcs_tx_eq_info tx;
+ struct mxl862xx_xpcs_rx_eq_info rx;
+} __packed;
+
+/**
+ * struct mxl862xx_xpcs_signal_detect - signal detect status
+ * @port_id: XPCS port index (0 or 1)
+ * @rx_signal: RX signal detected
+ * @pma_link: PMA link up
+ * @link_fault: PCS link fault
+ * @in_reset: XPCS in reset
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_signal_detect {
+ u8 port_id:2;
+ u8 rx_signal:1;
+ u8 pma_link:1;
+ u8 link_fault:1;
+ u8 in_reset:1;
+ u8 __rsv:2;
+ u8 __pad;
+ __le16 result;
+} __packed;
+
#endif /* __MXL862XX_API_H */
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -83,6 +83,8 @@
#define MXL862XX_XPCS_FORCE_SPEED (MXL862XX_XPCS_MAGIC + 0x7)
@@ -79,6 +79,7 @@
#define MXL862XX_XPCS_PCS_LINK_UP (MXL862XX_XPCS_MAGIC + 0x7)
#define MXL862XX_XPCS_LOOPBACK (MXL862XX_XPCS_MAGIC + 0x8)
#define MXL862XX_XPCS_RESET (MXL862XX_XPCS_MAGIC + 0x9)
+#define MXL862XX_XPCS_EQ_GET (MXL862XX_XPCS_MAGIC + 0xc)
+#define MXL862XX_XPCS_SIGNAL_DETECT (MXL862XX_XPCS_MAGIC + 0xd)
#define MMD_API_MAXIMUM_ID 0x7fff
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
@@ -456,3 +456,96 @@ const struct phylink_mac_ops mxl862xx_ph
@@ -414,3 +414,100 @@ const struct phylink_mac_ops mxl862xx_ph
.mac_link_up = mxl862xx_phylink_mac_link_up,
.mac_select_pcs = mxl862xx_phylink_mac_select_pcs,
};
@@ -152,18 +153,19 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ "serdes_rx_dfe_bypass",
+ "serdes_rx_adapt_mode",
+ "serdes_rx_adapt_sel",
+ "serdes_rx_signal",
+ "serdes_pma_link",
+ "serdes_link_fault",
+ "serdes_in_reset",
+};
+
+static bool mxl862xx_port_has_serdes_stats(struct dsa_switch *ds, int port)
+{
+ struct mxl862xx_priv *priv = ds->priv;
+
+ return port >= 9 && port <= 16 &&
+ MXL862XX_FW_VER_MIN(priv, 1, 0, 80);
+ /* Firmware reads EQ/signal status per XPCS, not per lane. Expose
+ * the stats only on the slot-0 port of each XPCS (9 and 13) so
+ * users don't see four duplicate copies labelled as if they were
+ * independent per-port readings.
+ */
+ return (port == 9 || port == 13) &&
+ MXL862XX_FW_VER_MIN(priv, 1, 0, 84);
+}
+
+int mxl862xx_serdes_stats_count(struct dsa_switch *ds, int port)
@@ -185,50 +187,53 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ ethtool_puts(&data, mxl862xx_serdes_stats[i]);
+}
+
+static u64 mxl862xx_eq_effective(const struct mxl862xx_xpcs_eq_item *it)
+{
+ return it->ovrd_en ? it->ovrd : it->value;
+}
+
+void mxl862xx_serdes_get_stats(struct dsa_switch *ds, int port, u64 *data)
+{
+ struct mxl862xx_xpcs_eq_get eq = {
+ .port_id = mxl862xx_xpcs_port_id(port),
+ .port_id = MXL862XX_SERDES_PORT_ID(port),
+ };
+ struct mxl862xx_xpcs_signal_detect sig = {};
+ int ret;
+
+ if (!mxl862xx_port_has_serdes_stats(ds, port))
+ return;
+
+ sig.port_id = mxl862xx_xpcs_port_id(port);
+
+ if (!MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_EQ_GET, eq)) {
+ *data++ = eq.tx.main.value;
+ *data++ = eq.tx.pre.value;
+ *data++ = eq.tx.post.value;
+ *data++ = eq.tx.iboost_lvl.value;
+ *data++ = eq.tx.vboost_lvl.value;
+ *data++ = eq.tx.vboost_en.value;
+ *data++ = eq.rx.att_lvl.value;
+ *data++ = eq.rx.vga1_gain.value;
+ *data++ = eq.rx.vga2_gain.value;
+ *data++ = eq.rx.ctle_boost.value;
+ *data++ = eq.rx.ctle_pole.value;
+ *data++ = eq.rx.dfe_tap1.value;
+ *data++ = eq.rx.dfe_bypass.value;
+ *data++ = eq.rx.adapt_mode.value;
+ *data++ = eq.rx.adapt_sel.value;
+ } else {
+ data += 15;
+ ret = MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_EQ_GET, eq);
+ if (ret) {
+ dev_err(ds->dev,
+ "port %d: XPCS EQ_GET failed: %d\n", port, ret);
+ return;
+ }
+ if ((s16)le16_to_cpu(eq.result) < 0) {
+ dev_err(ds->dev,
+ "port %d: XPCS EQ_GET firmware result: %d\n",
+ port, (s16)le16_to_cpu(eq.result));
+ return;
+ }
+
+ if (!MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_SIGNAL_DETECT, sig)) {
+ *data++ = sig.rx_signal;
+ *data++ = sig.pma_link;
+ *data++ = sig.link_fault;
+ *data++ = sig.in_reset;
+ } else {
+ data += 4;
+ }
+ *data++ = mxl862xx_eq_effective(&eq.tx.main);
+ *data++ = mxl862xx_eq_effective(&eq.tx.pre);
+ *data++ = mxl862xx_eq_effective(&eq.tx.post);
+ *data++ = mxl862xx_eq_effective(&eq.tx.iboost_lvl);
+ *data++ = mxl862xx_eq_effective(&eq.tx.vboost_lvl);
+ *data++ = mxl862xx_eq_effective(&eq.tx.vboost_en);
+ *data++ = mxl862xx_eq_effective(&eq.rx.att_lvl);
+ *data++ = mxl862xx_eq_effective(&eq.rx.vga1_gain);
+ *data++ = mxl862xx_eq_effective(&eq.rx.vga2_gain);
+ *data++ = mxl862xx_eq_effective(&eq.rx.ctle_boost);
+ *data++ = mxl862xx_eq_effective(&eq.rx.ctle_pole);
+ *data++ = mxl862xx_eq_effective(&eq.rx.dfe_tap1);
+ *data++ = mxl862xx_eq_effective(&eq.rx.dfe_bypass);
+ *data++ = mxl862xx_eq_effective(&eq.rx.adapt_mode);
+ *data++ = mxl862xx_eq_effective(&eq.rx.adapt_sel);
+}
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
@@ -12,5 +12,8 @@ void mxl862xx_phylink_get_caps(struct ds
@@ -17,5 +17,8 @@ void mxl862xx_phylink_get_caps(struct ds
struct phylink_config *config);
void mxl862xx_setup_pcs(struct mxl862xx_priv *priv, struct mxl862xx_pcs *pcs,
int port);
@@ -239,7 +244,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#endif /* __MXL862XX_PHYLINK_H */
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -1775,6 +1775,8 @@ static void mxl862xx_get_strings(struct
@@ -1776,6 +1776,8 @@ static void mxl862xx_get_strings(struct
for (i = 0; i < ARRAY_SIZE(mxl862xx_mib); i++)
ethtool_puts(&data, mxl862xx_mib[i].name);
@@ -248,7 +253,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
static int mxl862xx_get_sset_count(struct dsa_switch *ds, int port, int sset)
@@ -1782,7 +1784,7 @@ static int mxl862xx_get_sset_count(struc
@@ -1783,7 +1785,7 @@ static int mxl862xx_get_sset_count(struc
if (sset != ETH_SS_STATS)
return 0;
@@ -257,7 +262,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
static int mxl862xx_read_rmon(struct dsa_switch *ds, int port,
@@ -1818,6 +1820,8 @@ static void mxl862xx_get_ethtool_stats(s
@@ -1819,6 +1821,8 @@ static void mxl862xx_get_ethtool_stats(s
else
*data++ = le64_to_cpu(*(__le64 *)field);
}
@@ -1,208 +0,0 @@
From ce66c0be462c8500dfc483395e68be4326ebf296 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:15:32 +0000
Subject: [PATCH 06/19] net: dsa: mxl862xx: add SerDes self-test via PRBS and
BERT
Implement the dsa_switch_ops.self_test callback for SerDes ports
(9-16). Two loopback tests are run:
1. PCS-level PRBS31: enables TX/RX PRBS31 pattern at the PCS layer,
waits 100ms, then reads the error counter.
2. SerDes-level BERT PRBS31: enables TX/RX BERT with PRBS31 pattern
at the SerDes layer, waits 100ms, then reads the error counter.
Both tests clean up (disable pattern generators) regardless of outcome.
Gated on firmware >= 1.0.80 via mxl862xx_port_has_serdes_stats().
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 45 +++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 85 +++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 1 +
5 files changed, 136 insertions(+)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -1900,4 +1900,49 @@ struct mxl862xx_xpcs_signal_detect {
__le16 result;
} __packed;
+/**
+ * struct mxl862xx_xpcs_prbs_cfg - PCS-level PRBS31 test pattern
+ * @port_id: XPCS port index (0 or 1)
+ * @tx_en: TX PRBS31 enable
+ * @rx_en: RX PRBS31 enable
+ * @read_err: read error count
+ * @rx_err_cnt: RX PRBS31 error count (valid when read_err=1)
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_prbs_cfg {
+ u8 port_id:2;
+ u8 tx_en:1;
+ u8 rx_en:1;
+ u8 read_err:1;
+ u8 __rsv:3;
+ u8 __pad;
+ __le16 rx_err_cnt;
+ __le16 result;
+} __packed;
+
+/**
+ * struct mxl862xx_xpcs_bert_cfg - SerDes-level BERT test pattern
+ * @port_id: XPCS port index (0 or 1)
+ * @tx_en: TX BERT enable
+ * @rx_en: RX BERT enable
+ * @read_err: read RX error count
+ * @clear_err: clear RX error counter
+ * @insert_err: insert one TX error
+ * @pattern: PRBS pattern type (1-7; 0 = disable)
+ * @rx_err_cnt: RX BERT error count (valid when read_err=1)
+ * @result: firmware result
+ */
+struct mxl862xx_xpcs_bert_cfg {
+ u8 port_id:2;
+ u8 tx_en:1;
+ u8 rx_en:1;
+ u8 read_err:1;
+ u8 clear_err:1;
+ u8 insert_err:1;
+ u8 __rsv:1;
+ u8 pattern;
+ __le16 rx_err_cnt;
+ __le16 result;
+} __packed;
+
#endif /* __MXL862XX_API_H */
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -83,6 +83,8 @@
#define MXL862XX_XPCS_FORCE_SPEED (MXL862XX_XPCS_MAGIC + 0x7)
#define MXL862XX_XPCS_LOOPBACK (MXL862XX_XPCS_MAGIC + 0x8)
#define MXL862XX_XPCS_RESET (MXL862XX_XPCS_MAGIC + 0x9)
+#define MXL862XX_XPCS_PRBS_CFG (MXL862XX_XPCS_MAGIC + 0xa)
+#define MXL862XX_XPCS_BERT_CFG (MXL862XX_XPCS_MAGIC + 0xb)
#define MXL862XX_XPCS_EQ_GET (MXL862XX_XPCS_MAGIC + 0xc)
#define MXL862XX_XPCS_SIGNAL_DETECT (MXL862XX_XPCS_MAGIC + 0xd)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
@@ -549,3 +549,88 @@ void mxl862xx_serdes_get_stats(struct ds
data += 4;
}
}
+
+void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
+ struct ethtool_test *etest, u64 *data)
+{
+ struct mxl862xx_xpcs_prbs_cfg prbs = {};
+ struct mxl862xx_xpcs_bert_cfg bert = {};
+ struct mxl862xx_priv *priv = ds->priv;
+ int xpcs_id = mxl862xx_xpcs_port_id(port);
+ int i = 0;
+ int ret;
+
+ if (!mxl862xx_port_has_serdes_stats(ds, port))
+ return;
+
+ /* Test 1: PCS PRBS31 */
+ prbs.port_id = xpcs_id;
+ prbs.tx_en = 1;
+ prbs.rx_en = 1;
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
+ if (ret) {
+ data[i++] = 1;
+ goto skip_prbs;
+ }
+
+ msleep(100);
+
+ memset(&prbs, 0, sizeof(prbs));
+ prbs.port_id = xpcs_id;
+ prbs.read_err = 1;
+ ret = MXL862XX_API_READ(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
+
+ /* Disable PRBS */
+ memset(&prbs, 0, sizeof(prbs));
+ prbs.port_id = xpcs_id;
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
+
+ if (ret) {
+ data[i++] = 1;
+ } else {
+ data[i] = le16_to_cpu(prbs.rx_err_cnt) ? 1 : 0;
+ if (data[i])
+ etest->flags |= ETH_TEST_FL_FAILED;
+ i++;
+ }
+
+skip_prbs:
+ /* Test 2: SerDes BERT PRBS31 -- clear error counter first */
+ bert.port_id = xpcs_id;
+ bert.clear_err = 1;
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
+
+ /* Enable BERT with PRBS31 pattern */
+ memset(&bert, 0, sizeof(bert));
+ bert.port_id = xpcs_id;
+ bert.tx_en = 1;
+ bert.rx_en = 1;
+ bert.pattern = 6; /* PRBS31 */
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
+ if (ret) {
+ data[i++] = 1;
+ return;
+ }
+
+ msleep(100);
+
+ /* Read error count */
+ memset(&bert, 0, sizeof(bert));
+ bert.port_id = xpcs_id;
+ bert.read_err = 1;
+ ret = MXL862XX_API_READ(priv, MXL862XX_XPCS_BERT_CFG, bert);
+
+ /* Disable BERT */
+ memset(&bert, 0, sizeof(bert));
+ bert.port_id = xpcs_id;
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
+
+ if (ret) {
+ data[i++] = 1;
+ } else {
+ data[i] = le16_to_cpu(bert.rx_err_cnt) ? 1 : 0;
+ if (data[i])
+ etest->flags |= ETH_TEST_FL_FAILED;
+ i++;
+ }
+}
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
@@ -3,6 +3,7 @@
#ifndef __MXL862XX_PHYLINK_H
#define __MXL862XX_PHYLINK_H
+#include <linux/ethtool.h>
#include <linux/phylink.h>
#include "mxl862xx.h"
@@ -15,5 +16,7 @@ void mxl862xx_setup_pcs(struct mxl862xx_
int mxl862xx_serdes_stats_count(struct dsa_switch *ds, int port);
void mxl862xx_serdes_get_strings(struct dsa_switch *ds, int port, u8 *data);
void mxl862xx_serdes_get_stats(struct dsa_switch *ds, int port, u64 *data);
+void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
+ struct ethtool_test *etest, u64 *data);
#endif /* __MXL862XX_PHYLINK_H */
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -2088,6 +2088,7 @@ static const struct dsa_switch_ops mxl86
.get_pause_stats = mxl862xx_get_pause_stats,
.get_rmon_stats = mxl862xx_get_rmon_stats,
.get_stats64 = mxl862xx_get_stats64,
+ .self_test = mxl862xx_serdes_self_test,
};
static int mxl862xx_probe(struct mdio_device *mdiodev)
@@ -1,7 +1,7 @@
From e6defbd42db6e64c2bb203f82b7d7f8c0691a052 Mon Sep 17 00:00:00 2001
From 50a84327282120a51af12da91214ed9e06f585cb Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:51:13 +0000
Subject: [PATCH 07/19] net: dsa: mxl862xx: trap link-local and multicast
Subject: [PATCH 06/19] net: dsa: mxl862xx: trap link-local and multicast
snooping frames to CPU
Install per-CTP PCE rules on each user port that trap IEEE 802.1D
@@ -19,10 +19,21 @@ all flood modes enabled. Each trap rule points the bridge engine at
this FID via bFidEnable so that IGMP and MLD frames are never
silently dropped by the ingress port's private flood policy.
Three multicast snooping rules are installed per port:
offset 2 -- IPv4 IGMP (IP protocol 2, all versions)
offset 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
offset 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
Rules are written through the firmware's logical-index API,
GSW_TFLOW_PCERULELOGICWRITE. The firmware translates the logical
index in @rule->pattern.index into a physical position within the
per-CTP block selected by @rule->region and @rule->logicalportid,
and grows the hardware block size on demand as rules are inserted.
A single dispatch helper, mxl862xx_pce_rule_write(), centralises the
firmware command so the trap callers do not need to know which API
variant is used. Four logical indices are consumed in each port's
per-CTP block (index 0 is reserved by the firmware for its
flow-control marking rule):
index 1 -- IEEE 802.1D link-local (dst 01:80:c2:00:00:0x)
index 2 -- IPv4 IGMP (IP protocol 2, all versions)
index 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
index 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
Add the PCE rule firmware API structures, command definitions, and
the rule block allocation interface.
@@ -30,15 +41,15 @@ the rule block allocation interface.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 684 ++++++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 5 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 186 +++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 6 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 198 +++++++
drivers/net/dsa/mxl862xx/mxl862xx.h | 8 +
4 files changed, 883 insertions(+)
4 files changed, 896 insertions(+)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -1420,6 +1420,690 @@ struct mxl862xx_port_link_cfg {
u8 lpi;
@@ -1184,6 +1184,690 @@ struct mxl862xx_ctp_port_assignment {
__le16 bridge_port_id;
} __packed;
+/* PCE (Packet Classification Engine) rule structures.
@@ -694,7 +705,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * @action: Forwarding action (portmap, cross-state, etc.)
+ *
+ * This structure is passed to the firmware via the MDIO data
+ * buffer using the %MXL862XX_TFLOW_PCERULEWRITE command.
+ * buffer using the %MXL862XX_TFLOW_PCERULELOGICWRITE command.
+ * The binary layout must exactly match the firmware's
+ * GSW_PCE_rule_t (466 bytes, packed, little-endian scalars).
+ */
@@ -738,13 +749,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#define MXL862XX_BRDG_MAGIC 0x300
#define MXL862XX_BRDGPORT_MAGIC 0x400
#define MXL862XX_CTP_MAGIC 0x500
@@ -31,6 +32,10 @@
@@ -30,6 +31,11 @@
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
+#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
+#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
+#define MXL862XX_TFLOW_PCERULEFREE (MXL862XX_TFLOW_MAGIC + 0x5)
+#define MXL862XX_TFLOW_PCERULELOGICWRITE \
+ (MXL862XX_TFLOW_MAGIC + 0xa)
+
#define MXL862XX_BRIDGE_ALLOC (MXL862XX_BRDG_MAGIC + 0x1)
#define MXL862XX_BRIDGE_CONFIGSET (MXL862XX_BRDG_MAGIC + 0x2)
@@ -771,21 +783,35 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return 0;
not_ready_yet:
@@ -381,6 +384,158 @@ static int mxl862xx_setup_drop_meter(str
@@ -381,6 +384,170 @@ static int mxl862xx_setup_drop_meter(str
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
}
+
+/* Per-CTP offsets for protocol trap rules. Each port's CTP flow-table
+ * block is pre-allocated by the firmware during init (44 entries per
+ * port on a 10-port SKU, of which offset 0 is reserved for flow-control
+ * marking). Offsets 1-4 are used for link-local and multicast snooping
+ * traps; all others remain free.
+/* Per-CTP logical indices for protocol trap rules.
+ *
+ * The firmware pre-allocates a per-CTP PCE block for every port during
+ * init and reserves logical index 0 for its flow-control marking rule.
+ * Logical indices 1-4 are used here for link-local and multicast
+ * snooping traps; the firmware grows the underlying hardware block on
+ * demand as PCERULELOGICWRITE inserts new entries.
+ */
+#define MXL862XX_LINK_LOCAL_CTP_OFFSET 1
+#define MXL862XX_IGMP_CTP_OFFSET 2
+#define MXL862XX_MLDV1_CTP_OFFSET 3
+#define MXL862XX_MLDV2_CTP_OFFSET 4
+#define MXL862XX_LINK_LOCAL_CTP_INDEX 1
+#define MXL862XX_IGMP_CTP_INDEX 2
+#define MXL862XX_MLDV1_CTP_INDEX 3
+#define MXL862XX_MLDV2_CTP_INDEX 4
+
+/* Install (or overwrite) a PCE rule via the firmware's logical-index
+ * API. The firmware translates the logical index in @rule->pattern.index
+ * to a physical position within the block selected by @rule->region and
+ * @rule->logicalportid, and expands the hardware block size as needed.
+ */
+static int mxl862xx_pce_rule_write(struct mxl862xx_priv *priv,
+ struct mxl862xx_pce_rule *rule)
+{
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULELOGICWRITE,
+ *rule);
+}
+
+/* Fill the action fields of a PCE rule that traps ingress frames to
+ * the CPU port. Used by both the link-local trap and the multicast
@@ -826,12 +852,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * The firmware does not install this rule by default because its own
+ * STP module is not used when DSA manages STP.
+ *
+ * The rule is written into the port's per-CTP flow table at offset 1.
+ * The firmware already allocates a 44-entry block for every CTP during
+ * init (8 entries exposed initially, expandable), so no dynamic
+ * allocation via PCERULEALLOC is needed. Using region=CTP causes the
+ * firmware to translate the CTP-relative offset into an absolute
+ * hardware index.
+ * The rule is written into the port's per-CTP flow table at logical
+ * index 1 using PCERULELOGICWRITE, which selects the per-CTP block via
+ * @region and @logicalportid and grows the block on demand.
+ *
+ * Cross-state is enabled so that link-local frames reach the CPU even
+ * when the bridge port is in BLOCKING or LEARNING state.
@@ -844,7 +867,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ rule.logicalportid = port;
+ rule.region = cpu_to_le32(MXL862XX_PCE_RULE_CTP);
+
+ rule.pattern.index = cpu_to_le16(MXL862XX_LINK_LOCAL_CTP_OFFSET);
+ rule.pattern.index = cpu_to_le16(MXL862XX_LINK_LOCAL_CTP_INDEX);
+ rule.pattern.enable = 1;
+ rule.pattern.mac_dst_enable = 1;
+ memcpy(rule.pattern.mac_dst, eth_reserved_addr_base, ETH_ALEN);
@@ -852,7 +875,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
+
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
+ return mxl862xx_pce_rule_write(priv, &rule);
+}
+
+/* Install PCE rules that trap IGMP and MLD frames to the CPU port for
@@ -862,10 +885,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * never classified as blocked unknown MC regardless of the ingress
+ * port's standalone flood policy.
+ *
+ * Three rules are installed per port:
+ * offset 2 -- IPv4 IGMP (IP protocol 2, all versions)
+ * offset 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
+ * offset 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
+ * Three rules are installed per port at logical indices in the per-CTP
+ * block:
+ * index 2 -- IPv4 IGMP (IP protocol 2, all versions)
+ * index 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
+ * index 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
+ *
+ * The MLDv1 rule uses range mode on the first two bytes after the IP
+ * header (ICMPv6 type + code): lower bound 0x8200 (type 130, code 0)
@@ -883,12 +907,12 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
+
+ /* IGMP: IPv4 protocol 2, all versions */
+ rule.pattern.index = cpu_to_le16(MXL862XX_IGMP_CTP_OFFSET);
+ rule.pattern.index = cpu_to_le16(MXL862XX_IGMP_CTP_INDEX);
+ rule.pattern.enable = 1;
+ rule.pattern.protocol = IPPROTO_IGMP;
+ rule.pattern.protocol_enable = 1;
+
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
+ ret = mxl862xx_pce_rule_write(priv, &rule);
+ if (ret)
+ return ret;
+
@@ -896,7 +920,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * Range mode covers all three types with any code value.
+ */
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV1_CTP_OFFSET);
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV1_CTP_INDEX);
+ rule.pattern.enable = 1;
+ rule.pattern.protocol = IPPROTO_ICMPV6;
+ rule.pattern.protocol_enable = 1;
@@ -907,7 +931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ rule.pattern.app_data_msb_enable = 1;
+ rule.pattern.app_mask_range_msb_select = 1; /* range mode */
+
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
+ ret = mxl862xx_pce_rule_write(priv, &rule);
+ if (ret)
+ return ret;
+
@@ -915,7 +939,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ * Nibble mask 0x3 masks nibbles 0-1 (lower byte = code field).
+ */
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV2_CTP_OFFSET);
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV2_CTP_INDEX);
+ rule.pattern.enable = 1;
+ rule.pattern.protocol = IPPROTO_ICMPV6;
+ rule.pattern.protocol_enable = 1;
@@ -924,13 +948,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ rule.pattern.app_data_msb_enable = 1;
+ /* app_mask_range_msb_select = 0: nibble mask mode (default) */
+
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
+ return mxl862xx_pce_rule_write(priv, &rule);
+}
+
static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
{
struct mxl862xx_bridge_port_config br_port_cfg = {};
@@ -683,6 +838,28 @@ static int mxl862xx_setup(struct dsa_swi
@@ -684,6 +851,28 @@ static int mxl862xx_setup(struct dsa_swi
if (ret)
return ret;
@@ -959,7 +983,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
schedule_delayed_work(&priv->stats_work,
MXL862XX_STATS_POLL_INTERVAL);
@@ -1382,6 +1559,15 @@ static int mxl862xx_port_setup(struct ds
@@ -1383,6 +1572,15 @@ static int mxl862xx_port_setup(struct ds
if (ret)
return ret;
@@ -977,7 +1001,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -319,6 +319,13 @@ union mxl862xx_fw_version {
@@ -317,6 +317,13 @@ struct mxl862xx_fw_version {
* @evlan_ingress_size: per-port ingress Extended VLAN block size
* @evlan_egress_size: per-port egress Extended VLAN block size
* @vf_block_size: per-port VLAN Filter block size
@@ -991,7 +1015,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @stats_work: periodic work item that polls RMON hardware counters
* and accumulates them into 64-bit per-port stats
*/
@@ -335,6 +342,7 @@ struct mxl862xx_priv {
@@ -334,6 +341,7 @@ struct mxl862xx_priv {
u16 evlan_ingress_size;
u16 evlan_egress_size;
u16 vf_block_size;
@@ -1,7 +1,7 @@
From 264838ee8ee3ad611a84df96d889429f1ded2148 Mon Sep 17 00:00:00 2001
From 6126dff8c28e71091c23fd0cc2f55b1a50e117a6 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:51:21 +0000
Subject: [PATCH 08/19] net: dsa: mxl862xx: warn about old firmware default PCE
Subject: [PATCH 07/19] net: dsa: mxl862xx: warn about old firmware default PCE
rules
Firmware versions older than 1.0.80 install global PCE rules at
@@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -860,6 +860,10 @@ static int mxl862xx_setup(struct dsa_swi
@@ -873,6 +873,10 @@ static int mxl862xx_setup(struct dsa_swi
true, true, true);
if (ret)
return ret;
@@ -1,7 +1,7 @@
From d7ed9b681298d206d81e9cf3c93558d6e912ae88 Mon Sep 17 00:00:00 2001
From 69a0946ef48325b85f4a331152d6340f39083053 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Sun, 22 Mar 2026 00:58:04 +0000
Subject: [PATCH 09/20] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx
Subject: [PATCH 08/19] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx
The MxL862xx native 8-byte special tag (SpTag) requires firmware
support on the switch CPU and is not compatible with all SoC Ethernet
@@ -22,13 +22,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
drivers/net/dsa/mxl862xx/Kconfig | 1 +
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 221 +++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 1678 ++++++++++++++++++++---
drivers/net/dsa/mxl862xx/mxl862xx.c | 1677 ++++++++++++++++++++---
drivers/net/dsa/mxl862xx/mxl862xx.h | 12 +
include/net/dsa.h | 2 +
net/dsa/Kconfig | 7 +
net/dsa/Makefile | 1 +
net/dsa/tag_mxl862xx_8021q.c | 65 +
9 files changed, 1803 insertions(+), 186 deletions(-)
9 files changed, 1804 insertions(+), 184 deletions(-)
create mode 100644 net/dsa/tag_mxl862xx_8021q.c
--- a/drivers/net/dsa/mxl862xx/Kconfig
@@ -43,10 +43,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
These switches have two 10GE SerDes interfaces, one typically
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -1185,6 +1185,227 @@ struct mxl862xx_ctp_port_assignment {
@@ -1184,6 +1184,227 @@ struct mxl862xx_ctp_port_assignment {
__le16 bridge_port_id;
} __packed;
/**
+/**
+ * enum mxl862xx_ctp_port_config_mask - CTP Port Configuration Mask
+ * @MXL862XX_CTP_PORT_CONFIG_MASK_BRIDGE_PORT_ID:
+ * Mask for bridge_port_id.
@@ -267,10 +268,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ u8 egress_mirror_enable;
+} __packed;
+
+/**
* enum mxl862xx_port_duplex - Ethernet port duplex status
* @MXL862XX_DUPLEX_FULL: Port operates in full-duplex mode
* @MXL862XX_DUPLEX_HALF: Port operates in half-duplex mode
/* PCE (Packet Classification Engine) rule structures.
*
* Binary layout must exactly match the firmware's GSW_PCE_rule_t
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -47,12 +47,14 @@
@@ -387,9 +387,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
/* PHY access via firmware relay */
@@ -396,6 +459,78 @@ static int mxl862xx_setup_drop_meter(str
#define MXL862XX_MLDV1_CTP_OFFSET 3
#define MXL862XX_MLDV2_CTP_OFFSET 4
@@ -410,6 +473,78 @@ static int mxl862xx_pce_rule_write(struc
*rule);
}
+/**
+ * mxl862xx_cpu_bridge_port_id - Get the bridge port ID for CPU-side forwarding
@@ -466,7 +466,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
/* Fill the action fields of a PCE rule that traps ingress frames to
* the CPU port. Used by both the link-local trap and the multicast
* snooping traps. The caller must already have set the rule header
@@ -404,24 +539,36 @@ static int mxl862xx_setup_drop_meter(str
@@ -418,24 +553,36 @@ static int mxl862xx_pce_rule_write(struc
* PORTMAP_ALTERNATIVE redirects the frame to the CPU port but does
* not by itself bypass downstream flood gates. In SpTag mode the
* ingress port's private FID may have forward_unknown_multicast=false,
@@ -505,17 +505,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
rule->action.cross_state_action =
cpu_to_le32(MXL862XX_PCE_ACTION_CROSS_STATE_CROSS);
@@ -441,9 +588,6 @@ static void mxl862xx_fill_cpu_trap_actio
* allocation via PCERULEALLOC is needed. Using region=CTP causes the
* firmware to translate the CTP-relative offset into an absolute
* hardware index.
- *
- * Cross-state is enabled so that link-local frames reach the CPU even
- * when the bridge port is in BLOCKING or LEARNING state.
*/
static int mxl862xx_setup_link_local_trap(struct dsa_switch *ds, int port)
{
@@ -552,11 +696,17 @@ static int mxl862xx_set_bridge_port(stru
@@ -564,11 +711,17 @@ static int mxl862xx_set_bridge_port(stru
return 0;
if (dsa_port_is_cpu(dp)) {
@@ -538,7 +528,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
} else if (dp->bridge) {
dsa_switch_for_each_bridge_member(member_dp, ds,
@@ -567,10 +717,10 @@ static int mxl862xx_set_bridge_port(stru
@@ -579,10 +732,10 @@ static int mxl862xx_set_bridge_port(stru
member_dp->index);
}
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
@@ -551,7 +541,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
p->flood_block = 0;
p->learning = false;
}
@@ -774,10 +924,12 @@ static void mxl862xx_free_bridge(struct
@@ -786,10 +939,12 @@ static void mxl862xx_free_bridge(struct
static int mxl862xx_setup(struct dsa_switch *ds)
{
struct mxl862xx_priv *priv = ds->priv;
@@ -566,16 +556,16 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = mxl862xx_reset(priv);
if (ret)
@@ -790,7 +942,7 @@ static int mxl862xx_setup(struct dsa_swi
for (i = 0; i < 8; i++)
mxl862xx_setup_pcs(priv, &priv->serdes_ports[i], i + 9);
@@ -803,7 +958,7 @@ static int mxl862xx_setup(struct dsa_swi
mxl862xx_setup_pcs(priv, &priv->serdes_ports[i],
i + MXL862XX_FIRST_SERDES_PORT);
- /* Calculate Extended VLAN block sizes.
+ /* Calculate Extended VLAN and VLAN Filter block sizes.
* With VLAN Filter handling VID membership checks:
* Ingress: only final catchall rules (PVID insertion, 802.1Q
* accept, non-8021Q TPID handling, discard).
@@ -798,46 +950,151 @@ static int mxl862xx_setup(struct dsa_swi
@@ -811,46 +966,151 @@ static int mxl862xx_setup(struct dsa_swi
* ingress EVLAN rules are needed. (7 entries.)
* Egress: 2 rules per VID that needs tag stripping (untagged VIDs).
* No egress final catchalls -- VLAN Filter does the discard.
@@ -739,7 +729,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
/* Allocate a dedicated PCE snooping FID with all flood modes enabled.
* Per-port PCE trap rules (link-local, IGMP, MLD) set bFidEnable to
@@ -860,10 +1117,6 @@ static int mxl862xx_setup(struct dsa_swi
@@ -873,10 +1133,6 @@ static int mxl862xx_setup(struct dsa_swi
true, true, true);
if (ret)
return ret;
@@ -750,7 +740,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
schedule_delayed_work(&priv->stats_work,
MXL862XX_STATS_POLL_INTERVAL);
@@ -944,10 +1197,71 @@ static int mxl862xx_configure_sp_tag_pro
@@ -957,10 +1213,71 @@ static int mxl862xx_configure_sp_tag_pro
return MXL862XX_API_WRITE(ds->priv, MXL862XX_SS_SPTAG_SET, tag);
}
@@ -823,7 +813,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
{
struct mxl862xx_extendedvlan_config cfg = {};
struct mxl862xx_extendedvlan_filter_vlan *fv;
@@ -1016,6 +1330,31 @@ static int mxl862xx_evlan_write_rule(str
@@ -1029,6 +1346,31 @@ static int mxl862xx_evlan_write_rule(str
cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM);
}
break;
@@ -855,7 +845,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
return MXL862XX_API_WRITE(priv, MXL862XX_EXTENDEDVLAN_SET, cfg);
@@ -1054,7 +1393,7 @@ static int mxl862xx_evlan_write_final_ru
@@ -1067,7 +1409,7 @@ static int mxl862xx_evlan_write_final_ru
for (i = 0; i < n_rules; i++) {
ret = mxl862xx_evlan_write_rule(priv, blk->block_id,
start_idx + i, &rules[i],
@@ -864,7 +854,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
}
@@ -1175,6 +1514,41 @@ static int mxl862xx_vf_del_vid(struct mx
@@ -1188,6 +1530,41 @@ static int mxl862xx_vf_del_vid(struct mx
return 0;
}
@@ -906,7 +896,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int mxl862xx_evlan_program_ingress(struct mxl862xx_priv *priv, int port)
{
struct mxl862xx_port *p = &priv->ports[port];
@@ -1199,8 +1573,8 @@ static int mxl862xx_evlan_program_egress
@@ -1212,8 +1589,8 @@ static int mxl862xx_evlan_program_egress
const struct mxl862xx_evlan_rule_desc *vid_rules;
struct mxl862xx_vf_vid *vfv;
u16 old_active = blk->n_active;
@@ -916,7 +906,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (p->vlan_filtering) {
vid_rules = vid_accept_standard;
@@ -1214,13 +1588,23 @@ static int mxl862xx_evlan_program_egress
@@ -1227,13 +1604,23 @@ static int mxl862xx_evlan_program_egress
if (!vfv->untagged)
continue;
@@ -941,7 +931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
@@ -1229,7 +1613,29 @@ static int mxl862xx_evlan_program_egress
@@ -1242,7 +1629,29 @@ static int mxl862xx_evlan_program_egress
idx++, &vid_rules[1],
vfv->vid,
vfv->untagged,
@@ -972,7 +962,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
}
@@ -1241,8 +1647,7 @@ static int mxl862xx_evlan_program_egress
@@ -1254,8 +1663,7 @@ static int mxl862xx_evlan_program_egress
*/
for (i = idx; i < old_active; i++) {
ret = mxl862xx_evlan_deactivate_entry(priv,
@@ -982,7 +972,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
}
@@ -1267,13 +1672,16 @@ static int mxl862xx_port_vlan_filtering(
@@ -1280,13 +1688,16 @@ static int mxl862xx_port_vlan_filtering(
p->vlan_filtering = vlan_filtering;
if (changed) {
@@ -1004,7 +994,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = mxl862xx_evlan_program_ingress(priv, port);
if (ret)
@@ -1493,22 +1901,575 @@ static void mxl862xx_port_bridge_leave(s
@@ -1506,22 +1917,575 @@ static void mxl862xx_port_bridge_leave(s
port, ERR_PTR(err));
/* Revert leaving port, omitted by the sync above, to its
@@ -1582,7 +1572,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int mxl862xx_port_setup(struct dsa_switch *ds, int port)
{
struct mxl862xx_priv *priv = ds->priv;
@@ -1530,33 +2491,52 @@ static int mxl862xx_port_setup(struct ds
@@ -1543,33 +2507,52 @@ static int mxl862xx_port_setup(struct ds
return -EOPNOTSUPP;
}
@@ -1651,7 +1641,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
return ret;
ret = mxl862xx_set_bridge_port(ds, port);
@@ -1572,24 +2552,7 @@ static int mxl862xx_port_setup(struct ds
@@ -1585,24 +2568,7 @@ static int mxl862xx_port_setup(struct ds
if (ret)
return ret;
@@ -1676,7 +1666,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return 0;
}
@@ -1611,7 +2574,7 @@ static void mxl862xx_port_teardown(struc
@@ -1624,7 +2590,7 @@ static void mxl862xx_port_teardown(struc
priv->ports[port].setup_done = false;
}
@@ -1685,7 +1675,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
{
struct mxl862xx_priv *priv = ds->priv;
@@ -1629,23 +2592,247 @@ static int mxl862xx_get_fid(struct dsa_s
@@ -1642,23 +2608,247 @@ static int mxl862xx_get_fid(struct dsa_s
}
}
@@ -1718,12 +1708,12 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ if (dsa_is_cpu_port(ds, port) && priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q &&
+ db.type == DSA_DB_PORT) {
+ bp_cpu = priv->ports[db.dp->index].bridge_port_cpu;
+
- param.port_id = cpu_to_le32(port);
+ if (bp_cpu)
+ return bp_cpu;
+ }
- param.port_id = cpu_to_le32(port);
+
+ return port;
+}
+
@@ -1941,7 +1931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
dev_err(ds->dev, "failed to add FDB entry on port %d\n", port);
@@ -1655,18 +2842,25 @@ static int mxl862xx_port_fdb_add(struct
@@ -1668,18 +2858,25 @@ static int mxl862xx_port_fdb_add(struct
static int mxl862xx_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid, const struct dsa_db db)
{
@@ -1950,7 +1940,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct mxl862xx_priv *priv = ds->priv;
+ struct dsa_port *target_dp;
+ int fid, ret;
+
+ /* Mirror of the standalone->bridge FID path in fdb_add */
+ if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && dsa_is_cpu_port(ds, port) &&
+ db.type == DSA_DB_PORT && vid > 0) {
@@ -1960,7 +1950,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ mxl862xx_fdb_del_per_fid(ds, addr, vid,
+ priv->bridges[target_dp->bridge->num]);
+ }
+
+ fid = mxl862xx_get_fid(ds, db);
if (fid < 0)
return fid;
@@ -1974,7 +1964,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
dev_err(ds->dev, "failed to remove FDB entry on port %d\n", port);
@@ -1705,84 +2899,153 @@ static int mxl862xx_port_fdb_dump(struct
@@ -1718,84 +2915,153 @@ static int mxl862xx_port_fdb_dump(struct
return 0;
}
@@ -2075,7 +2065,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
- sizeof(aparam.port_map));
+ return ret;
+}
+
- mxl862xx_fw_portmap_set_bit(aparam.port_map, port);
+/**
+ * mxl862xx_mac_del_host_bridge - Remove every user-port VBP bit from a host
+ * FDB/MDB entry, dropping the entry when its
@@ -2099,14 +2090,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ struct dsa_port *dp;
+ u16 vbp;
- mxl862xx_fw_portmap_set_bit(aparam.port_map, port);
- return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYADD, aparam);
+ dsa_switch_for_each_user_port(dp, ds) {
+ vbp = priv->ports[dp->index].bridge_port_cpu;
+ if (vbp)
+ mxl862xx_fw_portmap_set_bit(del_map, vbp);
+ }
- return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYADD, aparam);
+
+ return mxl862xx_mac_portmap_del(priv, addr, fid, vid, del_map);
}
@@ -2120,7 +2110,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
- int fid = mxl862xx_get_fid(ds, db), ret;
struct mxl862xx_priv *priv = ds->priv;
+ int fid, ret;
+
+ /* tag_8021q host MDB for bridged ports: clear all VBP bits */
+ if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && dsa_is_cpu_port(ds, port) &&
+ db.type == DSA_DB_BRIDGE) {
@@ -2130,7 +2120,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ return mxl862xx_mac_del_host_bridge(ds, mdb->addr,
+ mdb->vid, &db.bridge);
+ }
+
+ fid = mxl862xx_get_fid(ds, db);
if (fid < 0)
return fid;
@@ -2175,7 +2165,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return ret;
}
@@ -1867,6 +3130,9 @@ static void mxl862xx_host_flood_work_fn(
@@ -1880,6 +3146,9 @@ static void mxl862xx_host_flood_work_fn(
host_flood_work);
struct mxl862xx_priv *priv = p->priv;
struct dsa_switch *ds = priv->ds;
@@ -2185,7 +2175,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
rtnl_lock();
@@ -1876,13 +3142,34 @@ static void mxl862xx_host_flood_work_fn(
@@ -1889,13 +3158,34 @@ static void mxl862xx_host_flood_work_fn(
return;
}
@@ -2227,7 +2217,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
rtnl_unlock();
}
@@ -2248,7 +3535,9 @@ static void mxl862xx_get_stats64(struct
@@ -2261,7 +3551,9 @@ static void mxl862xx_get_stats64(struct
static const struct dsa_switch_ops mxl862xx_switch_ops = {
.get_tag_protocol = mxl862xx_get_tag_protocol,
@@ -2237,7 +2227,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.port_setup = mxl862xx_port_setup,
.port_teardown = mxl862xx_port_teardown,
.phylink_get_caps = mxl862xx_phylink_get_caps,
@@ -2270,6 +3559,8 @@ static const struct dsa_switch_ops mxl86
@@ -2283,6 +3575,8 @@ static const struct dsa_switch_ops mxl86
.port_vlan_filtering = mxl862xx_port_vlan_filtering,
.port_vlan_add = mxl862xx_port_vlan_add,
.port_vlan_del = mxl862xx_port_vlan_del,
@@ -2246,7 +2236,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_strings = mxl862xx_get_strings,
.get_sset_count = mxl862xx_get_sset_count,
.get_ethtool_stats = mxl862xx_get_ethtool_stats,
@@ -2318,6 +3609,8 @@ static int mxl862xx_probe(struct mdio_de
@@ -2330,6 +3624,8 @@ static int mxl862xx_probe(struct mdio_de
INIT_DELAYED_WORK(&priv->stats_work, mxl862xx_stats_work_fn);
@@ -2255,7 +2245,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
dev_set_drvdata(dev, ds);
err = dsa_register_switch(ds);
@@ -2346,6 +3639,19 @@ static void mxl862xx_remove(struct mdio_
@@ -2358,6 +3654,19 @@ static void mxl862xx_remove(struct mdio_
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
cancel_delayed_work_sync(&priv->stats_work);
@@ -2277,7 +2267,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
mxl862xx_host_shutdown(priv);
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -209,6 +209,9 @@ struct mxl862xx_port_stats {
@@ -212,6 +212,9 @@ struct mxl862xx_port_stats {
* @vf: per-port VLAN Filter block state
* @ingress_evlan: ingress extended VLAN block state
* @egress_evlan: egress extended VLAN block state
@@ -2287,7 +2277,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @host_flood_uc: desired host unicast flood state (true = flood);
* updated atomically by port_set_host_flood, consumed
* by the deferred host_flood_work
@@ -223,6 +226,7 @@ struct mxl862xx_port_stats {
@@ -226,6 +229,7 @@ struct mxl862xx_port_stats {
* periodically by the stats polling work
* @stats_lock: protects accumulator reads in .get_stats64 against
* concurrent updates from the polling work
@@ -2295,7 +2285,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
*/
struct mxl862xx_port {
struct mxl862xx_priv *priv;
@@ -235,9 +239,13 @@ struct mxl862xx_port {
@@ -238,9 +242,13 @@ struct mxl862xx_port {
struct mxl862xx_vf_block vf;
struct mxl862xx_evlan_block ingress_evlan;
struct mxl862xx_evlan_block egress_evlan;
@@ -2309,7 +2299,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct mxl862xx_port_stats stats;
spinlock_t stats_lock; /* protects stats accumulators */
};
@@ -304,6 +312,7 @@ union mxl862xx_fw_version {
@@ -298,6 +306,7 @@ struct mxl862xx_fw_version {
* before CRC-triggered shutdown and cleared after;
* %MXL862XX_FLAG_WORK_STOPPED is set before cancelling
* stats_work to prevent rescheduling during teardown
@@ -2317,7 +2307,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @drop_meter: index of the single shared zero-rate firmware meter
* used to unconditionally drop traffic (used to block
* flooding)
@@ -318,6 +327,7 @@ union mxl862xx_fw_version {
@@ -316,6 +325,7 @@ struct mxl862xx_fw_version {
* (0 .. ds->max_num_bridges).
* @evlan_ingress_size: per-port ingress Extended VLAN block size
* @evlan_egress_size: per-port egress Extended VLAN block size
@@ -2325,15 +2315,15 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @vf_block_size: per-port VLAN Filter block size
* @cpu_trap_fid: firmware bridge FID allocated for PCE-trapped frames;
* configured with uc/mc/bc flood all enabled so that
@@ -334,6 +344,7 @@ struct mxl862xx_priv {
@@ -332,6 +342,7 @@ struct mxl862xx_priv {
struct mdio_device *mdiodev;
struct work_struct crc_err_work;
unsigned long flags;
+ enum dsa_tag_protocol tag_proto;
u16 drop_meter;
union mxl862xx_fw_version fw_version;
struct mxl862xx_fw_version fw_version;
struct mxl862xx_pcs serdes_ports[8];
@@ -341,6 +352,7 @@ struct mxl862xx_priv {
@@ -340,6 +351,7 @@ struct mxl862xx_priv {
u16 bridges[MXL862XX_MAX_BRIDGES + 1];
u16 evlan_ingress_size;
u16 evlan_egress_size;
@@ -1,7 +1,7 @@
From a32f6a9c09b90e767a03ddac34d061545a0cf15e Mon Sep 17 00:00:00 2001
From 4220567bd18b2174c74e90d22f3bf47422c1fdf6 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 03:44:41 +0000
Subject: [PATCH 10/20] net: dsa: mxl862xx: add link aggregation support
Subject: [PATCH 09/19] net: dsa: mxl862xx: add link aggregation support
Implement LAG offloading via the firmware's trunking engine. A
dedicated firmware bridge port is allocated per LAG and remains
@@ -90,8 +90,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#define INT_GPHY_READ (GPY_GPY2XX_MAGIC + 0x1)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -680,7 +680,42 @@ static int mxl862xx_setup_snooping_traps
return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
@@ -695,7 +695,42 @@ static int mxl862xx_setup_snooping_traps
return mxl862xx_pce_rule_write(priv, &rule);
}
-static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
@@ -134,7 +134,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
{
struct mxl862xx_bridge_port_config br_port_cfg = {};
struct dsa_port *dp = dsa_to_port(ds, port);
@@ -713,8 +748,12 @@ static int mxl862xx_set_bridge_port(stru
@@ -728,8 +763,12 @@ static int mxl862xx_set_bridge_port(stru
dp->bridge->dev) {
if (member_dp->index == port)
continue;
@@ -149,7 +149,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
mxl862xx_cpu_bridge_port_id(ds, port));
@@ -727,7 +766,7 @@ static int mxl862xx_set_bridge_port(stru
@@ -742,7 +781,7 @@ static int mxl862xx_set_bridge_port(stru
bridge_id = dp->bridge ? priv->bridges[dp->bridge->num] : p->fid;
@@ -158,7 +158,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
br_port_cfg.bridge_id = cpu_to_le16(bridge_id);
br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_ID |
MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
@@ -808,11 +847,38 @@ static int mxl862xx_set_bridge_port(stru
@@ -823,11 +862,38 @@ static int mxl862xx_set_bridge_port(stru
br_port_cfg);
}
@@ -198,7 +198,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
dsa_switch_for_each_bridge_member(dp, ds, bridge->dev) {
err = mxl862xx_set_bridge_port(ds, dp->index);
@@ -820,6 +886,25 @@ static int mxl862xx_sync_bridge_members(
@@ -835,6 +901,25 @@ static int mxl862xx_sync_bridge_members(
ret = err;
}
@@ -224,7 +224,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return ret;
}
@@ -1859,6 +1944,408 @@ static int mxl862xx_setup_cpu_bridge(str
@@ -1875,6 +1960,408 @@ static int mxl862xx_setup_cpu_bridge(str
return mxl862xx_set_bridge_port(ds, port);
}
@@ -633,7 +633,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port,
const struct dsa_bridge bridge,
bool *tx_fwd_offload,
@@ -1884,7 +2371,18 @@ static int mxl862xx_port_bridge_join(str
@@ -1900,7 +2387,18 @@ static int mxl862xx_port_bridge_join(str
return 0;
}
@@ -653,7 +653,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port,
@@ -1935,6 +2433,17 @@ static void mxl862xx_port_bridge_leave(s
@@ -1951,6 +2449,17 @@ static void mxl862xx_port_bridge_leave(s
"failed to update CPU VBP for port %d: %pe\n", port,
ERR_PTR(err));
@@ -671,7 +671,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (!dsa_bridge_ports(ds, bridge.dev))
mxl862xx_free_bridge(ds, &bridge);
}
@@ -2593,18 +3102,17 @@ static int mxl862xx_get_fid(struct dsa_s
@@ -2609,18 +3118,17 @@ static int mxl862xx_get_fid(struct dsa_s
}
/**
@@ -697,7 +697,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
*/
static int mxl862xx_fdb_bridge_port(struct dsa_switch *ds, int port,
const struct dsa_db db)
@@ -2620,7 +3128,7 @@ static int mxl862xx_fdb_bridge_port(stru
@@ -2636,7 +3144,7 @@ static int mxl862xx_fdb_bridge_port(stru
return bp_cpu;
}
@@ -706,7 +706,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
}
/**
@@ -2867,11 +3375,43 @@ static int mxl862xx_port_fdb_del(struct
@@ -2883,11 +3391,43 @@ static int mxl862xx_port_fdb_del(struct
return ret;
}
@@ -750,7 +750,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
u32 entry_port_id;
int ret;
@@ -2885,7 +3425,7 @@ static int mxl862xx_port_fdb_dump(struct
@@ -2901,7 +3441,7 @@ static int mxl862xx_port_fdb_dump(struct
entry_port_id = le32_to_cpu(param.port_id);
@@ -759,7 +759,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = cb(param.mac, FIELD_GET(MXL862XX_TCI_VLAN_ID,
le16_to_cpu(param.tci)),
param.static_entry, data);
@@ -3556,6 +4096,11 @@ static const struct dsa_switch_ops mxl86
@@ -3572,6 +4112,11 @@ static const struct dsa_switch_ops mxl86
.port_fdb_dump = mxl862xx_port_fdb_dump,
.port_mdb_add = mxl862xx_port_mdb_add,
.port_mdb_del = mxl862xx_port_mdb_del,
@@ -771,7 +771,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.port_vlan_filtering = mxl862xx_port_vlan_filtering,
.port_vlan_add = mxl862xx_port_vlan_add,
.port_vlan_del = mxl862xx_port_vlan_del,
@@ -3597,6 +4142,7 @@ static int mxl862xx_probe(struct mdio_de
@@ -3612,6 +4157,7 @@ static int mxl862xx_probe(struct mdio_de
ds->num_ports = MXL862XX_MAX_PORTS;
ds->fdb_isolation = true;
ds->max_num_bridges = MXL862XX_MAX_BRIDGES;
@@ -781,7 +781,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -16,6 +16,19 @@ struct mxl862xx_priv;
@@ -19,6 +19,19 @@ struct mxl862xx_priv;
#define MXL862XX_MAX_BRIDGE_PORTS 128
#define MXL862XX_TOTAL_EVLAN_ENTRIES 1024
#define MXL862XX_TOTAL_VF_ENTRIES 1024
@@ -801,7 +801,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
/* Number of __le16 words in a firmware portmap (128-bit bitmap). */
#define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16)
@@ -227,6 +240,12 @@ struct mxl862xx_port_stats {
@@ -230,6 +243,12 @@ struct mxl862xx_port_stats {
* @stats_lock: protects accumulator reads in .get_stats64 against
* concurrent updates from the polling work
* @tag_8021q_vid: currently assigned tag_8021q management VID
@@ -814,7 +814,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
*/
struct mxl862xx_port {
struct mxl862xx_priv *priv;
@@ -246,6 +265,9 @@ struct mxl862xx_port {
@@ -249,6 +268,9 @@ struct mxl862xx_port {
struct work_struct host_flood_work;
u16 tag_8021q_vid;
struct mxl862xx_evlan_block cpu_egress_evlan;
@@ -824,7 +824,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct mxl862xx_port_stats stats;
spinlock_t stats_lock; /* protects stats accumulators */
};
@@ -336,6 +358,15 @@ union mxl862xx_fw_version {
@@ -334,6 +356,15 @@ struct mxl862xx_fw_version {
* policy. Set once in setup() and referenced by
* fill_cpu_trap_action() via bFidEnable. The PCE FID
* action field is 6 bits, so this value must be <= 63.
@@ -840,7 +840,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @stats_work: periodic work item that polls RMON hardware counters
* and accumulates them into 64-bit per-port stats
*/
@@ -355,6 +386,8 @@ struct mxl862xx_priv {
@@ -354,6 +385,8 @@ struct mxl862xx_priv {
u16 cpu_evlan_ingress_size;
u16 vf_block_size;
u16 cpu_trap_fid;
@@ -1,7 +1,7 @@
From d919c2f8da9dbd4dda57ceebb5c8b103805b58d1 Mon Sep 17 00:00:00 2001
From 8f7296099da5eaedfe5108a6fe93296bcc0c4b45 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 12:05:29 +0000
Subject: [PATCH 11/19] net: dsa: mxl862xx: add support for mirror port
Subject: [PATCH 10/19] net: dsa: mxl862xx: add support for mirror port
The MxL862xx hardware supports a single monitor port which can be
configured to mirror any other port's ingress and/or egress traffic.
@@ -40,17 +40,17 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @age_timer: Custom MAC table aging timer in seconds
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -30,6 +30,7 @@
#define MXL862XX_COMMON_PORTCFGGET (MXL862XX_COMMON_MAGIC + 0x7)
@@ -29,6 +29,7 @@
#define MXL862XX_COMMON_CFGGET (MXL862XX_COMMON_MAGIC + 0x9)
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
+#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -1100,6 +1100,8 @@ static int mxl862xx_setup(struct dsa_swi
@@ -1116,6 +1116,8 @@ static int mxl862xx_setup(struct dsa_swi
(n_user_ports + n_cpu_ports);
}
@@ -59,8 +59,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = mxl862xx_setup_drop_meter(ds);
if (ret)
return ret;
@@ -3167,6 +3169,120 @@ static int mxl862xx_fdb_del_per_fid(stru
return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYREMOVE, param);
@@ -1960,6 +1962,120 @@ static int mxl862xx_setup_cpu_bridge(str
return mxl862xx_set_bridge_port(ds, port);
}
+static int mxl862xx_port_mirror_add(struct dsa_switch *ds, int port,
@@ -178,9 +178,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+}
+
/**
* mxl862xx_mac_portmap_add - Set port bits in a MAC table entry's portmap
* @priv: driver private data
@@ -4096,6 +4212,8 @@ static const struct dsa_switch_ops mxl86
* mxl862xx_lag_master_port - Find the LAG master (lowest-numbered member)
* @ds: DSA switch
@@ -4112,6 +4228,8 @@ static const struct dsa_switch_ops mxl86
.port_fdb_dump = mxl862xx_port_fdb_dump,
.port_mdb_add = mxl862xx_port_mdb_add,
.port_mdb_del = mxl862xx_port_mdb_del,
@@ -191,7 +191,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.port_lag_change = mxl862xx_port_lag_change,
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -240,6 +240,8 @@ struct mxl862xx_port_stats {
@@ -243,6 +243,8 @@ struct mxl862xx_port_stats {
* @stats_lock: protects accumulator reads in .get_stats64 against
* concurrent updates from the polling work
* @tag_8021q_vid: currently assigned tag_8021q management VID
@@ -200,7 +200,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @lag: non-NULL when port is member of a LAG group;
* points to the DSA LAG structure
* @lag_tx_enabled: true when this port is active for TX in its LAG
@@ -265,6 +267,8 @@ struct mxl862xx_port {
@@ -268,6 +270,8 @@ struct mxl862xx_port {
struct work_struct host_flood_work;
u16 tag_8021q_vid;
struct mxl862xx_evlan_block cpu_egress_evlan;
@@ -209,7 +209,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct dsa_lag *lag;
bool lag_tx_enabled;
u8 lag_hash_bits;
@@ -367,6 +371,8 @@ union mxl862xx_fw_version {
@@ -365,6 +369,8 @@ struct mxl862xx_fw_version {
* @trunk_hash: current global hash field bitmask (6 bits,
* MXL862XX_TRUNK_HASH_*); union of all active LAGs'
* hash requirements
@@ -218,7 +218,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @stats_work: periodic work item that polls RMON hardware counters
* and accumulates them into 64-bit per-port stats
*/
@@ -388,6 +394,7 @@ struct mxl862xx_priv {
@@ -387,6 +393,7 @@ struct mxl862xx_priv {
u16 cpu_trap_fid;
u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
u8 trunk_hash;
@@ -1,7 +1,7 @@
From 64269d9d809962a0f7e68e9b618d81e561e3eb6f Mon Sep 17 00:00:00 2001
From d11e0b07317e04f347de1b5053bb6720d72fd111 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 16:30:08 +0000
Subject: [PATCH 12/19] net: dsa: wire flash_update devlink callback to drivers
Subject: [PATCH 11/19] net: dsa: wire flash_update devlink callback to drivers
Add a devlink_flash_update callback to dsa_switch_ops so that DSA
drivers can support devlink dev flash without open-coding the devlink
@@ -1,7 +1,7 @@
From fed4225f75b6fe6898e48f472cbbee0aaa046760 Mon Sep 17 00:00:00 2001
From 4dd558c7422fcd2b5c76994928fe3a65e0059fb4 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 16:30:17 +0000
Subject: [PATCH 13/19] net: dsa: mxl862xx: add SMDIO clause-22 register access
Subject: [PATCH 12/19] net: dsa: mxl862xx: add SMDIO clause-22 register access
Add mxl862xx_smdio_read() and mxl862xx_smdio_write() for clause-22
SMDIO register access. MCUboot rescue mode only exposes clause-22
@@ -1,7 +1,7 @@
From fa186b09e346e0b7f2504232731bc9e4dee0c600 Mon Sep 17 00:00:00 2001
From 099e70920b16f5da14d34bc00ac58a5ca95c1e33 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 16:30:31 +0000
Subject: [PATCH 14/19] net: dsa: mxl862xx: add devlink flash_update and
Subject: [PATCH 13/19] net: dsa: mxl862xx: add devlink flash_update and
info_get
Implement runtime firmware upgrade via "devlink dev flash" and version
@@ -35,9 +35,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
drivers/net/dsa/mxl862xx/mxl862xx-fw.c | 434 +++++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-fw.h | 15 +
drivers/net/dsa/mxl862xx/mxl862xx-host.c | 7 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 4 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 3 +
drivers/net/dsa/mxl862xx/mxl862xx.h | 2 +
7 files changed, 464 insertions(+), 1 deletion(-)
7 files changed, 463 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/dsa/mxl862xx/mxl862xx-fw.c
create mode 100644 drivers/net/dsa/mxl862xx/mxl862xx-fw.h
@@ -57,7 +57,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x1)
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x2)
#define MXL862XX_XPCS_MAGIC 0x1a00
#define MXL862XX_XPCS_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
--- /dev/null
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-fw.c
@@ -0,0 +1,434 @@
@@ -546,19 +546,18 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#include "mxl862xx-host.h"
#include "mxl862xx-phylink.h"
@@ -4233,6 +4234,9 @@ static const struct dsa_switch_ops mxl86
@@ -4248,6 +4249,8 @@ static const struct dsa_switch_ops mxl86
.get_pause_stats = mxl862xx_get_pause_stats,
.get_rmon_stats = mxl862xx_get_rmon_stats,
.get_stats64 = mxl862xx_get_stats64,
.self_test = mxl862xx_serdes_self_test,
+ .devlink_info_get = mxl862xx_devlink_info_get,
+ .devlink_flash_update = mxl862xx_devlink_flash_update,
+
};
static int mxl862xx_probe(struct mdio_device *mdiodev)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -395,6 +395,8 @@ struct mxl862xx_priv {
@@ -394,6 +394,8 @@ struct mxl862xx_priv {
u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
u8 trunk_hash;
int mirror_dest;
@@ -1,7 +1,7 @@
From 05bc981690d6ef03143a094f28714aa0171ab571 Mon Sep 17 00:00:00 2001
From d27d60f42f5188d6cfcb771d2188633f1031646f Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 1 Apr 2026 13:43:08 +0100
Subject: [PATCH 15/19] net: dsa: mxl862xx: implement port MTU configuration
Subject: [PATCH 14/19] net: dsa: mxl862xx: implement port MTU configuration
The firmware exposes a global max_packet_len register via
MXL862XX_COMMON_CFGSET. Since this is switch-wide rather than
@@ -25,7 +25,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
@@ -3727,6 +3728,53 @@ static int mxl862xx_set_ageing_time(stru
@@ -3743,6 +3744,53 @@ static int mxl862xx_set_ageing_time(stru
return ret;
}
@@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static void mxl862xx_port_stp_state_set(struct dsa_switch *ds, int port,
u8 state)
{
@@ -4202,6 +4250,8 @@ static const struct dsa_switch_ops mxl86
@@ -4218,6 +4266,8 @@ static const struct dsa_switch_ops mxl86
.port_disable = mxl862xx_port_disable,
.port_fast_age = mxl862xx_port_fast_age,
.set_ageing_time = mxl862xx_set_ageing_time,
@@ -90,7 +90,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.port_pre_bridge_flags = mxl862xx_port_pre_bridge_flags,
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -248,6 +248,8 @@ struct mxl862xx_port_stats {
@@ -251,6 +251,8 @@ struct mxl862xx_port_stats {
* @lag_hash_bits: hash field bitmask (MXL862XX_TRUNK_HASH_*) requested
* when this port joined its LAG; used to recompute the
* global trunk_hash when a LAG is destroyed
@@ -99,7 +99,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
*/
struct mxl862xx_port {
struct mxl862xx_priv *priv;
@@ -272,6 +274,7 @@ struct mxl862xx_port {
@@ -275,6 +277,7 @@ struct mxl862xx_port {
struct dsa_lag *lag;
bool lag_tx_enabled;
u8 lag_hash_bits;
@@ -1,7 +1,7 @@
From b723f7484006aadbaa51e16b870f3c98390605b1 Mon Sep 17 00:00:00 2001
From ba48edffc80f3dd676a9e8cf63aa4778a4ed0f0d Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 1 Apr 2026 13:43:12 +0100
Subject: [PATCH 16/19] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag
Subject: [PATCH 15/19] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag
Implement hairpin mode by including the port's own bridge port ID in
its forwarding portmap. When hairpin is enabled, bridged frames whose
@@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -759,6 +759,10 @@ static int __mxl862xx_set_bridge_port(st
@@ -774,6 +774,10 @@ static int __mxl862xx_set_bridge_port(st
}
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
mxl862xx_cpu_bridge_port_id(ds, port));
@@ -35,7 +35,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
} else {
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
mxl862xx_cpu_bridge_port_id(ds, port));
@@ -3895,7 +3899,7 @@ static int mxl862xx_port_pre_bridge_flag
@@ -3911,7 +3915,7 @@ static int mxl862xx_port_pre_bridge_flag
struct netlink_ext_ack *extack)
{
if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD |
@@ -44,7 +44,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return -EINVAL;
return 0;
@@ -3937,7 +3941,11 @@ static int mxl862xx_port_bridge_flags(st
@@ -3953,7 +3957,11 @@ static int mxl862xx_port_bridge_flags(st
if (flags.mask & BR_LEARNING)
priv->ports[port].learning = !!(flags.val & BR_LEARNING);
@@ -59,7 +59,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
if (ret)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -240,6 +240,10 @@ struct mxl862xx_port_stats {
@@ -243,6 +243,10 @@ struct mxl862xx_port_stats {
* @stats_lock: protects accumulator reads in .get_stats64 against
* concurrent updates from the polling work
* @tag_8021q_vid: currently assigned tag_8021q management VID
@@ -70,7 +70,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @ingress_mirror: true when ingress mirroring is active on this port
* @egress_mirror: true when egress mirroring is active on this port
* @lag: non-NULL when port is member of a LAG group;
@@ -269,6 +273,7 @@ struct mxl862xx_port {
@@ -272,6 +276,7 @@ struct mxl862xx_port {
struct work_struct host_flood_work;
u16 tag_8021q_vid;
struct mxl862xx_evlan_block cpu_egress_evlan;
@@ -1,7 +1,7 @@
From d8f20ba50ce0f93f34a41a9b833be76a5d1d2714 Mon Sep 17 00:00:00 2001
From 45fcd9669da62b27823004480c07854c54574a1a Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 25 Mar 2026 01:51:33 +0000
Subject: [PATCH 17/19] net: dsa: mxl862xx: support BR_ISOLATED bridge flag
Subject: [PATCH 16/19] net: dsa: mxl862xx: support BR_ISOLATED bridge flag
Implement port isolation by excluding isolated ports from each other's
forwarding portmaps in sync_bridge_members. Non-isolated ports can
@@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -752,6 +752,8 @@ static int __mxl862xx_set_bridge_port(st
@@ -767,6 +767,8 @@ static int __mxl862xx_set_bridge_port(st
continue;
if (!mxl862xx_is_lag_master(priv, member_dp->index))
continue;
@@ -28,7 +28,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
mxl862xx_fw_portmap_set_bit(
br_port_cfg.bridge_port_map,
mxl862xx_lag_bridge_port(priv,
@@ -3899,7 +3901,7 @@ static int mxl862xx_port_pre_bridge_flag
@@ -3915,7 +3917,7 @@ static int mxl862xx_port_pre_bridge_flag
struct netlink_ext_ack *extack)
{
if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD |
@@ -37,7 +37,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
return -EINVAL;
return 0;
@@ -3912,6 +3914,7 @@ static int mxl862xx_port_bridge_flags(st
@@ -3928,6 +3930,7 @@ static int mxl862xx_port_bridge_flags(st
struct mxl862xx_priv *priv = ds->priv;
unsigned long old_block = priv->ports[port].flood_block;
unsigned long block = old_block;
@@ -45,7 +45,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
int ret;
if (flags.mask & BR_FLOOD) {
@@ -3952,6 +3955,21 @@ static int mxl862xx_port_bridge_flags(st
@@ -3968,6 +3971,21 @@ static int mxl862xx_port_bridge_flags(st
return ret;
}
@@ -69,7 +69,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
@@ -213,6 +213,9 @@ struct mxl862xx_port_stats {
@@ -216,6 +216,9 @@ struct mxl862xx_port_stats {
* @flood_block: bitmask of firmware meter indices that are currently
* rate-limiting flood traffic on this port (zero-rate
* meters used to block flooding)
@@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
* @learning: true when address learning is enabled on this port
* @setup_done: set at end of port_setup, cleared at start of
* port_teardown; guards deferred work against
@@ -259,6 +262,7 @@ struct mxl862xx_port {
@@ -262,6 +265,7 @@ struct mxl862xx_port {
struct mxl862xx_priv *priv;
u16 fid;
unsigned long flood_block;
@@ -0,0 +1,134 @@
From 8120b9b88ec47ee41b8350e3e4341839f5fdc28e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:17:49 +0000
Subject: [PATCH 17/19] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE
workaround for old firmware
Re-introduce the legacy PCE rule paths needed for firmware versions
older than 1.0.83.
Firmware >= 1.0.83 exposes the new GSW_TFLOW_PCERULELOGICWRITE API
which selects the per-CTP block via @region/@logicalportid and grows
the hardware block on demand. Older firmware lacks that command and
exposes only the legacy GSW_TFLOW_PCERULEWRITE call, where the rule
index is a direct offset into a fixed-size pre-allocated CTP block.
Add MXL862XX_TFLOW_PCERULEWRITE back to mxl862xx-cmd.h and make
mxl862xx_pce_rule_write() pick the right command at runtime based on
the cached firmware version.
In addition, firmware older than 1.0.80 still installs global PCE
rules at boot that redirect link-local frames (BPDUs, LLDP, LACP) to
port 0 (the on-chip microcontroller) instead of the DSA CPU port.
With port 0 disabled under DSA these rules silently drop matching
traffic. Re-introduce mxl862xx_disable_fw_global_rules() to clear
them out during setup. The upstream submission replaced that call
with a dev_warn() since firmware >= 1.0.80 no longer installs the
problematic rules.
This commit is for downstream use only and must not be submitted
upstream.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
drivers/net/dsa/mxl862xx/mxl862xx.c | 61 +++++++++++++++++++++----
2 files changed, 53 insertions(+), 9 deletions(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -32,6 +32,7 @@
#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
+#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
#define MXL862XX_TFLOW_PCERULEFREE (MXL862XX_TFLOW_MAGIC + 0x5)
#define MXL862XX_TFLOW_PCERULELOGICWRITE \
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -449,6 +449,43 @@ static int mxl862xx_setup_drop_meter(str
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
}
+/* Disable firmware global PCE rules that trap various protocols to the
+ * on-die microcontroller (port 0) via PORTMAP_CPU. Under DSA, these
+ * frames must either reach the host CPU via per-port rules (link-local)
+ * or through the normal bridge forwarding path (ARP broadcast), so the
+ * global firmware rules are not needed. With the microcontroller port
+ * disabled they would silently drop matching traffic.
+ *
+ * Global rules have lower indices than CTP rules, hence higher priority
+ * in the PCE pipeline -- they must be explicitly disabled or they will
+ * shadow the per-CTP traps.
+ *
+ * Indices from gsw_flow_index.h:
+ * 1 -- BPDU (STP/RSTP, dst 01:80:c2:00:00:00)
+ * 3 -- LLDP (EtherType 0x88cc)
+ * 4 -- OAM/LACP (EtherType 0x8809)
+ * 6 -- System MAC (dst 02:e0:92:00:00:01, vendor management MAC)
+ * 7 -- ARP Request (broadcast + EtherType 0x0806 + TPA 192.0.2.1)
+ */
+static int mxl862xx_disable_fw_global_rules(struct dsa_switch *ds)
+{
+ static const u16 indices[] = { 1, 3, 4, 6, 7 };
+ struct mxl862xx_pce_rule rule;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(indices); i++) {
+ memset(&rule, 0, sizeof(rule));
+ rule.pattern.index = cpu_to_le16(indices[i]);
+ /* pattern.enable == 0 -> rule is disabled */
+
+ ret = MXL862XX_API_WRITE(ds->priv,
+ MXL862XX_TFLOW_PCERULEWRITE, rule);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
/* Per-CTP logical indices for protocol trap rules.
*
@@ -463,16 +500,20 @@ static int mxl862xx_setup_drop_meter(str
#define MXL862XX_MLDV1_CTP_INDEX 3
#define MXL862XX_MLDV2_CTP_INDEX 4
-/* Install (or overwrite) a PCE rule via the firmware's logical-index
- * API. The firmware translates the logical index in @rule->pattern.index
- * to a physical position within the block selected by @rule->region and
- * @rule->logicalportid, and expands the hardware block size as needed.
+/* Install (or overwrite) a PCE rule. On firmware >= 1.0.83 use the
+ * logical-index API (PCERULELOGICWRITE), which grows the per-CTP block
+ * on demand. On older firmware that API does not exist, so fall back
+ * to the legacy PCERULEWRITE call which uses the rule index as a
+ * direct offset into a fixed-size pre-allocated CTP block.
*/
static int mxl862xx_pce_rule_write(struct mxl862xx_priv *priv,
struct mxl862xx_pce_rule *rule)
{
- return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULELOGICWRITE,
- *rule);
+ u16 cmd = MXL862XX_FW_VER_MIN(priv, 1, 0, 83) ?
+ MXL862XX_TFLOW_PCERULELOGICWRITE :
+ MXL862XX_TFLOW_PCERULEWRITE;
+
+ return MXL862XX_API_WRITE(priv, cmd, *rule);
}
/**
@@ -1130,9 +1171,11 @@ static int mxl862xx_setup(struct dsa_swi
if (ret)
return ret;
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
- dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules "
- "that interfere with DSA operation, please update\n");
+ if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80)) {
+ ret = mxl862xx_disable_fw_global_rules(ds);
+ if (ret)
+ return ret;
+ }
/* Pre-allocate firmware resources for all ports. The DSA core
* calls change_tag_protocol() between setup() and port_setup(),
@@ -0,0 +1,491 @@
From 494a1eb62219d9ccb97a60e15ea59e7de2f5d9bc Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:19:56 +0000
Subject: [PATCH 18/19] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API
fallback for old firmware
Re-introduce the SYS_MISC_SFP_SET-based PCS implementation as a
fallback for firmware versions older than 1.0.84 which lack the
XPCS API. mxl862xx_setup_pcs() selects between the XPCS ops and
legacy SFP ops based on firmware version.
This commit is for downstream use only and must not be submitted
upstream.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 244 ++++++++++++++++++++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 3 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 155 ++++++++++++-
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
4 files changed, 401 insertions(+), 4 deletions(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -2164,6 +2164,18 @@ struct mxl862xx_sys_fw_image_version {
} __packed;
/**
+ * enum mxl862xx_port_duplex - Ethernet port duplex status
+ * @MXL862XX_DUPLEX_FULL: Port operates in full-duplex mode
+ * @MXL862XX_DUPLEX_HALF: Port operates in half-duplex mode
+ * @MXL862XX_DUPLEX_AUTO: Port operates in Auto mode
+ */
+enum mxl862xx_port_duplex {
+ MXL862XX_DUPLEX_FULL = 0,
+ MXL862XX_DUPLEX_HALF,
+ MXL862XX_DUPLEX_AUTO,
+};
+
+/**
* enum mxl862xx_port_type - Port Type
* @MXL862XX_LOGICAL_PORT: Logical Port
* @MXL862XX_PHYSICAL_PORT: Physical Port
@@ -2178,6 +2190,238 @@ enum mxl862xx_port_type {
};
/**
+ * enum mxl862xx_port_enable - port enable type selection.
+ * @MXL862XX_PORT_DISABLE: the port is disabled in both directions
+ * @MXL862XX_PORT_ENABLE_RXTX: the port is enabled in both directions
+ * @MXL862XX_PORT_ENABLE_RX: the port is enabled in the receive direction
+ * @MXL862XX_PORT_ENABLE_TX: the port is enabled in the transmit direction
+ */
+enum mxl862xx_port_enable {
+ MXL862XX_PORT_DISABLE = 0,
+ MXL862XX_PORT_ENABLE_RXTX,
+ MXL862XX_PORT_ENABLE_RX,
+ MXL862XX_PORT_ENABLE_TX,
+};
+
+/**
+ * enum mxl862xx_port_flow - ethernet flow control status
+ * @MXL862XX_FLOW_AUTO: automatic flow control
+ * @MXL862XX_FLOW_RX: receive flow control only
+ * @MXL862XX_FLOW_TX: transmit flow control only
+ * @MXL862XX_FLOW_RXTX: receive and transmit flow control
+ * @MXL862XX_FLOW_OFF: no flow control
+ */
+enum mxl862xx_port_flow {
+ MXL862XX_FLOW_AUTO = 0,
+ MXL862XX_FLOW_RX,
+ MXL862XX_FLOW_TX,
+ MXL862XX_FLOW_RXTX,
+ MXL862XX_FLOW_OFF,
+};
+
+/**
+ * enum mxl862xx_port_monitor - port mirror options
+ * @MXL862XX_PORT_MONITOR_NONE: mirroring is disabled
+ * @MXL862XX_PORT_MONITOR_RX: ingress packets are mirrored
+ * @MXL862XX_PORT_MONITOR_TX: egress packets are mirrored
+ * @MXL862XX_PORT_MONITOR_RXTX: ingress and egress packets are mirrored
+ * @MXL862XX_PORT_MONITOR_VLAN_UNKNOWN: mirroring of 'unknown VLAN violation' frames
+ * @MXL862XX_PORT_MONITOR_VLAN_MEMBERSHIP: mirroring of 'VLAN ingress or egress membership
+ * violation' frames
+ * @MXL862XX_PORT_MONITOR_PORT_STATE: mirroring of 'port state violation' frames
+ * @MXL862XX_PORT_MONITOR_LEARNING_LIMIT: mirroring of 'MAC learning limit violation' frames
+ * @MXL862XX_PORT_MONITOR_PORT_LOCK: mirroring of 'port lock violation' frames
+ */
+enum mxl862xx_port_monitor {
+ MXL862XX_PORT_MONITOR_NONE = 0,
+ MXL862XX_PORT_MONITOR_RX,
+ MXL862XX_PORT_MONITOR_TX,
+ MXL862XX_PORT_MONITOR_RXTX,
+ MXL862XX_PORT_MONITOR_VLAN_UNKNOWN,
+ MXL862XX_PORT_MONITOR_VLAN_MEMBERSHIP = 16,
+ MXL862XX_PORT_MONITOR_PORT_STATE = 32,
+ MXL862XX_PORT_MONITOR_LEARNING_LIMIT = 64,
+ MXL862XX_PORT_MONITOR_PORT_LOCK = 128,
+};
+
+/**
+ * enum mxl862xx_if_rmon_mode - interface RMON counter mode
+ * @MXL862XX_IF_RMON_FID: FID based RMON counters
+ * @MXL862XX_IF_RMON_SUBID: sub-interface ID based
+ * @MXL862XX_IF_RMON_FLOWID_LSB: flow ID based (bits 3:0)
+ * @MXL862XX_IF_RMON_FLOWID_MSB: flow ID based (bits 7:4)
+ */
+enum mxl862xx_if_rmon_mode {
+ MXL862XX_IF_RMON_FID = 0,
+ MXL862XX_IF_RMON_SUBID,
+ MXL862XX_IF_RMON_FLOWID_LSB,
+ MXL862XX_IF_RMON_FLOWID_MSB,
+};
+
+/**
+ * struct mxl862xx_port_cfg - Port Configuration Parameters
+ * @port_type: See &enum mxl862xx_port_type
+ * @port_id: Ethernet Port number (zero-based counting)
+ * @enable: See &enum mxl862xx_port_enable
+ * @unicast_unknown_drop: Drop unknown unicast packets
+ * @multicast_unknown_drop: Drop unknown multicast packets
+ * @reserved_packet_drop: Drop reserved packet types
+ * @broadcast_drop: Drop broadcast packets
+ * @aging: Enables MAC address table aging.
+ * @learning: MAC address table learning
+ * @learning_mac_port_lock: Automatic MAC address table learning locking on the port
+ * @learning_limit: Automatic MAC address table learning limitation on this port
+ * @mac_spoofing_detection: MAC spoofing detection. Identifies ingress packets that carry
+ * a MAC source address which was previously learned on a different ingress port
+ * @flow_ctrl: See &enum mxl862xx_port_flow
+ * @port_monitor: See &enum mxl862xx_port_monitor
+ * @if_counters: Assign Interface RMON Counters for this Port
+ * @if_count_start_idx: Interface RMON Counters Start Index
+ * @if_rmonmode: See &enum mxl862xx_if_rmon_mode
+ */
+struct mxl862xx_port_cfg {
+ __le32 port_type; /* enum mxl862xx_port_type */
+ __le16 port_id;
+ __le32 enable; /* enum mxl862xx_port_enable */
+ u8 unicast_unknown_drop;
+ u8 multicast_unknown_drop;
+ u8 reserved_packet_drop;
+ u8 broadcast_drop;
+ u8 aging;
+ u8 learning;
+ u8 learning_mac_port_lock;
+ __le16 learning_limit;
+ u8 mac_spoofing_detection;
+ __le32 flow_ctrl; /* enum mxl862xx_port_flow */
+ __le32 port_monitor; /* enum mxl862xx_port_monitor */
+ u8 if_counters;
+ __le32 if_count_start_idx;
+ __le32 if_rmonmode; /* enum mxl862xx_if_rmon_mode */
+} __packed;
+
+/**
+ * enum mxl862xx_port_speed - Ethernet port speed mode
+ * @MXL862XX_PORT_SPEED_10: 10 Mbit/s
+ * @MXL862XX_PORT_SPEED_100: 100 Mbit/s
+ * @MXL862XX_PORT_SPEED_200: 200 Mbit/s
+ * @MXL862XX_PORT_SPEED_1000: 1000 Mbit/s
+ * @MXL862XX_PORT_SPEED_2500: 2.5 Gbit/s
+ * @MXL862XX_PORT_SPEED_5000: 5 Gbit/s
+ * @MXL862XX_PORT_SPEED_10000: 10 Gbit/s
+ * @MXL862XX_PORT_SPEED_AUTO: Auto speed for XGMAC
+ */
+enum mxl862xx_port_speed {
+ MXL862XX_PORT_SPEED_10 = 0,
+ MXL862XX_PORT_SPEED_100,
+ MXL862XX_PORT_SPEED_200,
+ MXL862XX_PORT_SPEED_1000,
+ MXL862XX_PORT_SPEED_2500,
+ MXL862XX_PORT_SPEED_5000,
+ MXL862XX_PORT_SPEED_10000,
+ MXL862XX_PORT_SPEED_AUTO,
+};
+
+/**
+ * enum mxl862xx_port_link - Force the MAC and PHY link modus
+ * @MXL862XX_PORT_LINK_UP: Link up
+ * @MXL862XX_PORT_LINK_DOWN: Link down
+ * @MXL862XX_PORT_LINK_AUTO: Link Auto
+ */
+enum mxl862xx_port_link {
+ MXL862XX_PORT_LINK_UP = 0,
+ MXL862XX_PORT_LINK_DOWN,
+ MXL862XX_PORT_LINK_AUTO,
+};
+
+/**
+ * enum mxl862xx_mii_mode - Ethernet port interface mode
+ * @MXL862XX_PORT_HW_MII: Normal PHY interface
+ * @MXL862XX_PORT_HW_RMII: Reduced MII interface in normal mode
+ * @MXL862XX_PORT_HW_GMII: GMII or MII, depending upon the speed
+ * @MXL862XX_PORT_HW_RGMII: RGMII mode
+ * @MXL862XX_PORT_HW_XGMII: XGMII mode
+ */
+enum mxl862xx_mii_mode {
+ MXL862XX_PORT_HW_MII = 0,
+ MXL862XX_PORT_HW_RMII,
+ MXL862XX_PORT_HW_GMII,
+ MXL862XX_PORT_HW_RGMII,
+ MXL862XX_PORT_HW_XGMII,
+};
+
+/**
+ * enum mxl862xx_mii_type - Ethernet port configuration for PHY or MAC mode
+ * @MXL862XX_PORT_MAC: The Ethernet port is configured to work in MAC mode
+ * @MXL862XX_PORT_PHY: The Ethernet port is configured to work in PHY mode
+ */
+enum mxl862xx_mii_type {
+ MXL862XX_PORT_MAC = 0,
+ MXL862XX_PORT_PHY,
+};
+
+/**
+ * enum mxl862xx_clk_mode - Ethernet port clock source configuration
+ * @MXL862XX_PORT_CLK_NA: Clock Mode not applicable
+ * @MXL862XX_PORT_CLK_MASTER: Clock Master Mode.
+ * @MXL862XX_PORT_CLK_SLAVE: Clock Slave Mode.
+ */
+enum mxl862xx_clk_mode {
+ MXL862XX_PORT_CLK_NA = 0,
+ MXL862XX_PORT_CLK_MASTER,
+ MXL862XX_PORT_CLK_SLAVE,
+};
+
+/**
+ * struct mxl862xx_port_link_cfg - Ethernet port link, speed status and flow control status
+ * @port_id: Ethernet Port number
+ * @duplex_force: Force Port Duplex Mode
+ * @duplex: See &enum mxl862xx_port_duplex
+ * @speed_force: Force Link Speed
+ * @speed: See &enum mxl862xx_port_speed
+ * @link_force: Force Link
+ * @link: See &enum mxl862xx_port_link
+ * @mii_mode: See &enum mxl862xx_mii_mode
+ * @mii_type: See &enum mxl862xx_mii_type
+ * @clk_mode: See &enum mxl862xx_clk_mode
+ * @lpi: 'Low Power Idle' Support for 'Energy Efficient Ethernet'
+ */
+struct mxl862xx_port_link_cfg {
+ __le16 port_id;
+ u8 duplex_force;
+ __le32 duplex; /* enum mxl862xx_port_duplex */
+ u8 speed_force;
+ __le32 speed; /* enum mxl862xx_port_speed */
+ u8 link_force;
+ __le32 link; /* enum mxl862xx_port_link */
+ __le32 mii_mode; /* enum mxl862xx_mii_mode */
+ __le32 mii_type; /* enum mxl862xx_mii_type */
+ __le32 clk_mode; /* enum mxl862xx_clk_mode */
+ u8 lpi;
+} __packed;
+
+/**
+ * struct mxl862xx_sys_sfp_cfg - legacy SFP/SerDes port configuration
+ * @port_id: port id (0 or 1)
+ * @option: config options (0 - SFP mode/speed/link-status, 1 - flow control)
+ * @mode: SFP mode (0 - auto, 1 - fix, 2 - disable)
+ * @speed: select speed when mode is 1
+ * @link: get link state
+ * @fc_en: flow control (0 - disable, 1 - enable)
+ */
+struct mxl862xx_sys_sfp_cfg {
+ u8 port_id:4;
+ u8 option:4;
+ union {
+ struct {
+ u8 mode;
+ u8 speed;
+ u8 link;
+ };
+ u8 fc_en;
+ };
+} __packed;
+
+/**
* enum mxl862xx_rmon_port_type - RMON counter table type
* @MXL862XX_RMON_CTP_PORT_RX: CTP RX counters
* @MXL862XX_RMON_CTP_PORT_TX: CTP TX counters
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -27,6 +27,8 @@
#define SYS_MISC_MAGIC 0x1900
#define MXL862XX_XPCS_MAGIC 0x1a00
+#define MXL862XX_COMMON_PORTLINKCFGGET (MXL862XX_COMMON_MAGIC + 0x5)
+#define MXL862XX_COMMON_PORTCFGGET (MXL862XX_COMMON_MAGIC + 0x7)
#define MXL862XX_COMMON_CFGGET (MXL862XX_COMMON_MAGIC + 0x9)
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
@@ -86,6 +88,7 @@
#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x1)
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x2)
+#define SYS_MISC_SFP_SET (SYS_MISC_MAGIC + 0xe)
#define MXL862XX_XPCS_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
#define MXL862XX_XPCS_PCS_GET_STATE (MXL862XX_XPCS_MAGIC + 0x2)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
@@ -62,6 +62,153 @@ static struct mxl862xx_pcs *pcs_to_mxl86
return container_of(pcs, struct mxl862xx_pcs, pcs);
}
+/* Legacy SFP-based PCS implementation for firmware < 1.0.84 */
+static int mxl862xx_legacy_pcs_config(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct mxl862xx_pcs *mpcs = pcs_to_mxl862xx_pcs(pcs);
+ struct mxl862xx_priv *priv = mpcs->priv;
+ struct mxl862xx_sys_sfp_cfg ser_intf = {
+ .option = 0,
+ .mode = 1,
+ };
+
+ if (mpcs->slot != 0)
+ return 0;
+
+ ser_intf.port_id = mpcs->serdes_id;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ ser_intf.speed = 8;
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ ser_intf.speed = (neg_mode & PHYLINK_PCS_NEG_INBAND) ? 1 : 7;
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ ser_intf.speed = 4;
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ ser_intf.speed = 2;
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ ser_intf.speed = 3;
+ break;
+ default:
+ dev_err(priv->ds->dev, "unsupported interface: %s\n",
+ phy_modes(interface));
+ return -EINVAL;
+ }
+
+ return MXL862XX_API_WRITE(priv, SYS_MISC_SFP_SET, ser_intf);
+}
+
+static void mxl862xx_legacy_pcs_get_state(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ struct phylink_link_state *state)
+{
+ struct mxl862xx_pcs *mpcs = pcs_to_mxl862xx_pcs(pcs);
+ struct mxl862xx_priv *priv = mpcs->priv;
+ struct mxl862xx_port_link_cfg port_link_cfg = {
+ .port_id = cpu_to_le16(MXL862XX_PCS_PORT(mpcs)),
+ };
+ struct mxl862xx_port_cfg port_cfg = {
+ .port_id = cpu_to_le16(MXL862XX_PCS_PORT(mpcs)),
+ };
+ int ret;
+
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTLINKCFGGET,
+ port_link_cfg);
+ if (ret)
+ return;
+
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTCFGGET, port_cfg);
+ if (ret)
+ return;
+
+ state->link = (le32_to_cpu(port_link_cfg.link) == MXL862XX_PORT_LINK_UP);
+ state->an_complete = state->link;
+
+ switch (le32_to_cpu(port_link_cfg.speed)) {
+ case MXL862XX_PORT_SPEED_10:
+ state->speed = SPEED_10;
+ break;
+ case MXL862XX_PORT_SPEED_100:
+ state->speed = SPEED_100;
+ break;
+ case MXL862XX_PORT_SPEED_1000:
+ state->speed = SPEED_1000;
+ break;
+ case MXL862XX_PORT_SPEED_2500:
+ state->speed = SPEED_2500;
+ break;
+ case MXL862XX_PORT_SPEED_5000:
+ state->speed = SPEED_5000;
+ break;
+ case MXL862XX_PORT_SPEED_10000:
+ state->speed = SPEED_10000;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ break;
+ }
+
+ switch (le32_to_cpu(port_link_cfg.duplex)) {
+ case MXL862XX_DUPLEX_HALF:
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MXL862XX_DUPLEX_FULL:
+ state->duplex = DUPLEX_FULL;
+ break;
+ default:
+ state->duplex = DUPLEX_UNKNOWN;
+ break;
+ }
+
+ state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
+ switch (le32_to_cpu(port_cfg.flow_ctrl)) {
+ case MXL862XX_FLOW_RXTX:
+ state->pause |= MLO_PAUSE_TXRX_MASK;
+ break;
+ case MXL862XX_FLOW_TX:
+ state->pause |= MLO_PAUSE_TX;
+ break;
+ case MXL862XX_FLOW_RX:
+ state->pause |= MLO_PAUSE_RX;
+ break;
+ case MXL862XX_FLOW_OFF:
+ default:
+ break;
+ }
+}
+
+static unsigned int
+mxl862xx_legacy_pcs_inband_caps(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ return LINK_INBAND_DISABLE;
+ default:
+ return 0;
+ }
+}
+
+static const struct phylink_pcs_ops mxl862xx_legacy_pcs_ops = {
+ .pcs_get_state = mxl862xx_legacy_pcs_get_state,
+ .pcs_config = mxl862xx_legacy_pcs_config,
+ .pcs_inband_caps = mxl862xx_legacy_pcs_inband_caps,
+};
+
static int mxl862xx_xpcs_if_mode(phy_interface_t interface)
{
switch (interface) {
@@ -352,7 +499,10 @@ void mxl862xx_setup_pcs(struct mxl862xx_
pcs->slot = MXL862XX_SERDES_SLOT(port);
pcs->interface = PHY_INTERFACE_MODE_NA;
- pcs->pcs.ops = &mxl862xx_pcs_ops;
+ if (MXL862XX_FW_VER_MIN(priv, 1, 0, 84))
+ pcs->pcs.ops = &mxl862xx_pcs_ops;
+ else
+ pcs->pcs.ops = &mxl862xx_legacy_pcs_ops;
pcs->pcs.poll = true;
__set_bit(PHY_INTERFACE_MODE_QSGMII, pcs->pcs.supported_interfaces);
@@ -376,9 +526,6 @@ mxl862xx_phylink_mac_select_pcs(struct p
struct mxl862xx_priv *priv = dp->ds->priv;
int port = dp->index;
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 84))
- return NULL;
-
switch (port) {
case 9 ... 16:
return &priv->serdes_ports[port - 9].pcs;
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
@@ -11,6 +11,9 @@
(((port) - MXL862XX_FIRST_SERDES_PORT) % MXL862XX_SERDES_SLOTS)
#define MXL862XX_SERDES_PORT_ID(port) \
(((port) - MXL862XX_FIRST_SERDES_PORT) / MXL862XX_SERDES_SLOTS)
+#define MXL862XX_PCS_PORT(mpcs) \
+ (MXL862XX_FIRST_SERDES_PORT + \
+ (mpcs)->serdes_id * MXL862XX_SERDES_SLOTS + (mpcs)->slot)
extern const struct phylink_mac_ops mxl862xx_phylink_mac_ops;
void mxl862xx_phylink_get_caps(struct dsa_switch *ds, int port,
@@ -1,81 +0,0 @@
From 8856f7610167a3005ecef401c8528111d153b554 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:17:49 +0000
Subject: [PATCH 18/19] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE
workaround for old firmware
Re-introduce the mxl862xx_disable_fw_global_rules() function that
disables firmware default global PCE rules for firmware versions
older than 1.0.80. The upstream submission replaced this with a
dev_warn() since firmware >= 1.0.80 no longer installs these rules,
but downstream deployments may still run older firmware.
This commit is for downstream use only and must not be submitted
upstream.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx.c | 45 +++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 3 deletions(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -449,6 +449,43 @@ static int mxl862xx_setup_drop_meter(str
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
}
+/* Disable firmware global PCE rules that trap various protocols to the
+ * on-die microcontroller (port 0) via PORTMAP_CPU. Under DSA, these
+ * frames must either reach the host CPU via per-port rules (link-local)
+ * or through the normal bridge forwarding path (ARP broadcast), so the
+ * global firmware rules are not needed. With the microcontroller port
+ * disabled they would silently drop matching traffic.
+ *
+ * Global rules have lower indices than CTP rules, hence higher priority
+ * in the PCE pipeline -- they must be explicitly disabled or they will
+ * shadow the per-CTP traps.
+ *
+ * Indices from gsw_flow_index.h:
+ * 1 -- BPDU (STP/RSTP, dst 01:80:c2:00:00:00)
+ * 3 -- LLDP (EtherType 0x88cc)
+ * 4 -- OAM/LACP (EtherType 0x8809)
+ * 6 -- System MAC (dst 02:e0:92:00:00:01, vendor management MAC)
+ * 7 -- ARP Request (broadcast + EtherType 0x0806 + TPA 192.0.2.1)
+ */
+static int mxl862xx_disable_fw_global_rules(struct dsa_switch *ds)
+{
+ static const u16 indices[] = { 1, 3, 4, 6, 7 };
+ struct mxl862xx_pce_rule rule;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(indices); i++) {
+ memset(&rule, 0, sizeof(rule));
+ rule.pattern.index = cpu_to_le16(indices[i]);
+ /* pattern.enable == 0 -> rule is disabled */
+
+ ret = MXL862XX_API_WRITE(ds->priv,
+ MXL862XX_TFLOW_PCERULEWRITE, rule);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
/* Per-CTP offsets for protocol trap rules. Each port's CTP flow-table
* block is pre-allocated by the firmware during init (44 entries per
@@ -1114,9 +1151,11 @@ static int mxl862xx_setup(struct dsa_swi
if (ret)
return ret;
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
- dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules "
- "that interfere with DSA operation, please update\n");
+ if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80)) {
+ ret = mxl862xx_disable_fw_global_rules(ds);
+ if (ret)
+ return ret;
+ }
/* Pre-allocate firmware resources for all ports. The DSA core
* calls change_tag_protocol() between setup() and port_setup(),
@@ -1,7 +1,7 @@
From df0c747216063041ba0d786b01f9b1e2aba5316a Mon Sep 17 00:00:00 2001
From 332dd61f50b096256f889ecb4d730d385e58aec2 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 22 Apr 2026 15:15:52 +0100
Subject: [PATCH] DO NOT SUBMIT: net: dsa: mxl862xx: increase CMD timeout
Subject: [PATCH 19/19] DO NOT SUBMIT: net: dsa: mxl862xx: increase CMD timeout
Lift the command timeout by 10x from 500ms to 5s.
This is done because older firmware can be extremely slow to respond
@@ -1,252 +0,0 @@
From 20be48bbcc89f5ca91e9d6adadeda9bd29d75c53 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 24 Mar 2026 18:19:56 +0000
Subject: [PATCH 19/19] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API
fallback for old firmware
Re-introduce the SYS_MISC_SFP_SET-based PCS implementation as a
fallback for firmware versions older than 1.0.80 which lack the
XPCS API. mxl862xx_setup_pcs() selects between the XPCS ops and
legacy SFP ops based on firmware version.
This commit is for downstream use only and must not be submitted
upstream.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 22 +++
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 160 +++++++++++++++++++-
3 files changed, 178 insertions(+), 5 deletions(-)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
@@ -2400,6 +2400,28 @@ struct mxl862xx_sys_fw_image_version {
} __packed;
/**
+ * struct mxl862xx_sys_sfp_cfg - legacy SFP/SerDes port configuration
+ * @port_id: port id (0 or 1)
+ * @option: config options (0 - SFP mode/speed/link-status, 1 - flow control)
+ * @mode: SFP mode (0 - auto, 1 - fix, 2 - disable)
+ * @speed: select speed when mode is 1
+ * @link: get link state
+ * @fc_en: flow control (0 - disable, 1 - enable)
+ */
+struct mxl862xx_sys_sfp_cfg {
+ u8 port_id:4;
+ u8 option:4;
+ union {
+ struct {
+ u8 mode;
+ u8 speed;
+ u8 link;
+ };
+ u8 fc_en;
+ };
+} __packed;
+
+/**
* enum mxl862xx_rmon_port_type - RMON counter table type
* @MXL862XX_RMON_CTP_PORT_RX: CTP RX counters
* @MXL862XX_RMON_CTP_PORT_TX: CTP TX counters
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
@@ -85,6 +85,7 @@
#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x1)
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x2)
+#define SYS_MISC_SFP_SET (SYS_MISC_MAGIC + 0xe)
#define MXL862XX_XPCS_MAGIC 0x1a00
#define MXL862XX_XPCS_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
@@ -52,6 +52,156 @@ static struct mxl862xx_pcs *pcs_to_mxl86
return container_of(pcs, struct mxl862xx_pcs, pcs);
}
+/* Legacy SFP-based PCS implementation for firmware < 1.0.80 */
+static int mxl862xx_legacy_pcs_config(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct mxl862xx_priv *priv = pcs_to_mxl862xx_pcs(pcs)->priv;
+ int port = pcs_to_mxl862xx_pcs(pcs)->port;
+ struct mxl862xx_sys_sfp_cfg ser_intf = {
+ .option = 0,
+ .mode = 1,
+ };
+
+ if (port != 9 && port != 13)
+ return 0;
+
+ if (port == 9)
+ ser_intf.port_id = 0;
+ else
+ ser_intf.port_id = 1;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ ser_intf.speed = 8;
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ ser_intf.speed = (neg_mode & PHYLINK_PCS_NEG_INBAND) ? 1 : 7;
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ ser_intf.speed = 4;
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ ser_intf.speed = 2;
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ ser_intf.speed = 3;
+ break;
+ default:
+ dev_err(priv->ds->dev, "unsupported interface: %s\n",
+ phy_modes(interface));
+ return -EINVAL;
+ }
+
+ return MXL862XX_API_WRITE(priv, SYS_MISC_SFP_SET, ser_intf);
+}
+
+static void mxl862xx_legacy_pcs_get_state(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ struct phylink_link_state *state)
+{
+ struct mxl862xx_priv *priv = pcs_to_mxl862xx_pcs(pcs)->priv;
+ int port = pcs_to_mxl862xx_pcs(pcs)->port;
+ struct mxl862xx_port_link_cfg port_link_cfg = {
+ .port_id = port,
+ };
+ struct mxl862xx_port_cfg port_cfg = {
+ .port_id = port,
+ };
+ int ret;
+
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTLINKCFGGET,
+ port_link_cfg);
+ if (ret)
+ return;
+
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTCFGGET, port_cfg);
+ if (ret)
+ return;
+
+ state->link = (port_link_cfg.link == MXL862XX_PORT_LINK_UP);
+ state->an_complete = state->link;
+
+ switch (port_link_cfg.speed) {
+ case MXL862XX_PORT_SPEED_10:
+ state->speed = SPEED_10;
+ break;
+ case MXL862XX_PORT_SPEED_100:
+ state->speed = SPEED_100;
+ break;
+ case MXL862XX_PORT_SPEED_1000:
+ state->speed = SPEED_1000;
+ break;
+ case MXL862XX_PORT_SPEED_2500:
+ state->speed = SPEED_2500;
+ break;
+ case MXL862XX_PORT_SPEED_5000:
+ state->speed = SPEED_5000;
+ break;
+ case MXL862XX_PORT_SPEED_10000:
+ state->speed = SPEED_10000;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ break;
+ }
+
+ switch (port_link_cfg.duplex) {
+ case MXL862XX_DUPLEX_HALF:
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MXL862XX_DUPLEX_FULL:
+ state->duplex = DUPLEX_FULL;
+ break;
+ default:
+ state->duplex = DUPLEX_UNKNOWN;
+ break;
+ }
+
+ state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
+ switch (port_cfg.flow_ctrl) {
+ case MXL862XX_FLOW_RXTX:
+ state->pause |= MLO_PAUSE_TXRX_MASK;
+ break;
+ case MXL862XX_FLOW_TX:
+ state->pause |= MLO_PAUSE_TX;
+ break;
+ case MXL862XX_FLOW_RX:
+ state->pause |= MLO_PAUSE_RX;
+ break;
+ case MXL862XX_FLOW_OFF:
+ default:
+ break;
+ }
+}
+
+static unsigned int
+mxl862xx_legacy_pcs_inband_caps(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ return LINK_INBAND_DISABLE;
+ default:
+ return 0;
+ }
+}
+
+static const struct phylink_pcs_ops mxl862xx_legacy_pcs_ops = {
+ .pcs_get_state = mxl862xx_legacy_pcs_get_state,
+ .pcs_config = mxl862xx_legacy_pcs_config,
+ .pcs_inband_caps = mxl862xx_legacy_pcs_inband_caps,
+};
+
static int mxl862xx_xpcs_port_id(int port)
{
return port >= 13;
@@ -390,7 +540,10 @@ void mxl862xx_setup_pcs(struct mxl862xx_
pcs->priv = priv;
pcs->port = port;
- pcs->pcs.ops = &mxl862xx_pcs_ops;
+ if (MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
+ pcs->pcs.ops = &mxl862xx_pcs_ops;
+ else
+ pcs->pcs.ops = &mxl862xx_legacy_pcs_ops;
pcs->pcs.poll = true;
/* Sub-ports only support QSGMII (quad mode with dedicated
@@ -418,9 +571,6 @@ mxl862xx_phylink_mac_select_pcs(struct p
struct mxl862xx_priv *priv = dp->ds->priv;
int port = dp->index;
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
- return NULL;
-
switch (port) {
case 9 ... 16:
return &priv->serdes_ports[port - 9].pcs;
@@ -551,7 +701,7 @@ void mxl862xx_serdes_get_stats(struct ds
}
void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
- struct ethtool_test *etest, u64 *data)
+ struct ethtool_test *etest, u64 *data)
{
struct mxl862xx_xpcs_prbs_cfg prbs = {};
struct mxl862xx_xpcs_bert_cfg bert = {};
@@ -18,7 +18,8 @@ gw,imx8mp-gw72xx-2x|\
gw,imx8mm-gw73xx-0x|\
gw,imx8mp-gw73xx-2x|\
gw,imx8mm-gw7902-0x|\
gateworks,imx8mp-gw82xx-2x)
gateworks,imx8mp-gw82xx-2x|\
kontron,imx8mp-bl-osm-s)
ucidef_set_interfaces_lan_wan 'eth1' 'eth0'
;;
gw,imx8mm-gw7901)
@@ -2,7 +2,8 @@
enable_image_metadata_check() {
case "$(board_name)" in
gateworks,imx8m*|\
gw,imx8m*)
gw,imx8m*|\
kontron,imx8mp-bl-osm-s)
REQUIRE_IMAGE_METADATA=1
;;
esac
@@ -14,7 +15,8 @@ platform_check_image() {
case "$board" in
gateworks,imx8m*|\
gw,imx8m*)
gw,imx8m*|\
kontron,imx8mp-bl-osm-s)
return 0
;;
esac
@@ -28,7 +30,8 @@ platform_do_upgrade() {
case "$board" in
gateworks,imx8m*|\
gw,imx8m*)
gw,imx8m*|\
kontron,imx8mp-bl-osm-s)
export_bootdevice && export_partdevice diskdev 0 || {
echo "Unable to find root device."
return 1
@@ -45,7 +48,8 @@ platform_copy_config() {
case "$board" in
gateworks,imx8m*|\
gw,imx8m*)
gw,imx8m*|\
kontron,imx8mp-bl-osm-s)
export_partdevice partdev 1 && {
v "Storing $UPGRADE_BACKUP on /dev/$partdev..."
mount -o rw,noatime "/dev/$partdev" /mnt

Some files were not shown because too many files have changed in this diff Show More