Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen
2026-03-08 16:13:59 +08:00
89 changed files with 2932 additions and 590 deletions
+22 -8
View File
@@ -13,7 +13,7 @@ include $(INCLUDE_DIR)/host-build.mk
define U-Boot/Default
BUILD_TARGET:=airoha
FIP_COMPRESS:=1
LZMA_COMPRESS:=1
endef
define U-Boot/en7523_rfb
@@ -46,10 +46,19 @@ define U-Boot/an7583_rfb
BL31_IMAGE:=an7583-bl31.bin
endef
define U-Boot/an7581_gemtek_w1700k
NAME:=Gemtek W1700K (UBI)
UBOOT_CONFIG:=an7581_w1700k
BUILD_DEVICES:=gemtek_w1700k-ubi
BUILD_SUBTARGET:=an7581
UBOOT_IMAGE:=u-boot.bin
endef
UBOOT_TARGETS := \
en7523_rfb \
an7581_rfb \
an7583_rfb
an7583_rfb \
an7581_gemtek_w1700k
UBOOT_CUSTOMIZE_CONFIG := \
--disable TOOLS_KWBIMAGE \
@@ -65,15 +74,12 @@ define Build/fip-image-bl2
endef
define Build/fip-image
$(if $(FIP_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
$(PKG_BUILD_DIR)/u-boot.bin \
$(PKG_BUILD_DIR)/u-boot.bin.lzma)
$(if $(FIP_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
$(if $(LZMA_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
files/$(BL31_IMAGE) \
$(PKG_BUILD_DIR)/bl31.bin.lzma)
$(STAGING_DIR_HOST)/bin/fiptool create \
--soc-fw $(PKG_BUILD_DIR)/bl31.bin$(if $(FIP_COMPRESS),.lzma) \
--nt-fw $(PKG_BUILD_DIR)/u-boot.bin$(if $(FIP_COMPRESS),.lzma) \
--soc-fw $(PKG_BUILD_DIR)/bl31.bin$(if $(LZMA_COMPRESS),.lzma) \
--nt-fw $(PKG_BUILD_DIR)/u-boot.bin$(if $(LZMA_COMPRESS),.lzma) \
$(PKG_BUILD_DIR)/u-boot.fip
endef
@@ -84,6 +90,9 @@ endef
define Build/Compile
$(call Build/Compile/U-Boot)
$(if $(LZMA_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
$(PKG_BUILD_DIR)/u-boot.bin \
$(PKG_BUILD_DIR)/u-boot.bin.lzma)
ifeq ($(UBOOT_IMAGE),u-boot.fip)
$(call Build/fip-image-bl2)
$(call Build/fip-image)
@@ -99,6 +108,11 @@ define Build/InstallDev
ifeq ($(UBOOT_IMAGE),u-boot.fip)
$(INSTALL_DATA) $(PKG_BUILD_DIR)/bl2.fip $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl2.fip
$(INSTALL_DATA) $(PKG_BUILD_DIR)/u-boot.fip $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl31-u-boot.fip
else
$(INSTALL_DATA) $(PKG_BUILD_DIR)/u-boot.bin$(if $(LZMA_COMPRESS),.lzma) \
$(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-u-boot.bin$(if $(LZMA_COMPRESS),.lzma)
$(INSTALL_DATA) $(PKG_BUILD_DIR)/u-boot.dtb \
$(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-u-boot.dtb
endif
endef
@@ -0,0 +1,21 @@
From 4fb890cd92dcf8985e76a544c949ad455784ed81 Mon Sep 17 00:00:00 2001
From: Dirk Buchwalder <buchwalder@posteo.de>
Date: Sun, 1 Mar 2026 13:48:42 +0100
Subject: [PATCH] uboot-airoha: add a label to the spi node
Signed-off-by: Dirk Buchwalder <buchwalder@posteo.de>
---
dts/upstream/src/arm64/airoha/en7581.dtsi | 2 -+
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/dts/upstream/src/arm64/airoha/en7581.dtsi
+++ b/dts/upstream/src/arm64/airoha/en7581.dtsi
@@ -150,7 +150,7 @@
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
};
- spi@1fa10000 {
+ snfi: spi@1fa10000 {
compatible = "airoha,en7581-snand";
reg = <0x0 0x1fa10000 0x0 0x140>,
<0x0 0x1fa11000 0x0 0x160>;
@@ -0,0 +1,318 @@
From d6402eadaa56494b382e389d739b9f80d6883788 Mon Sep 17 00:00:00 2001
From: Kenneth Kasilag <kenneth@kasilag.me>
Date: Sat, 21 Feb 2026 21:49:46 +0000
Subject: [PATCH] an7581: add uboot chainloader for w1700k
Due to issues surrounding the implementation of the vendor BMT/BBT
on Airoha, upstream ATF + uboot has switched to UBI flash partitions.
However, some devices shipped on this platform are bootloader locked,
and thus it is impossible to replace ATF + uboot.
During testing for the Gemtek W1700K (#17869), sysupgrades from Linux
(which is unaware of the underlying BMT/BBT) would occasionally write
data into blocks which were remapped by the vendor uboot when it was
read on the following reboot, causing a soft brick.
An acceptable workaround [1],[2] was discussed where an intermediate
uboot would be written by the vendor uboot (which is aware of Airoha
BMT/BBT). This chainloader would then ignore the regions of flash
used by the vendor uboot, and store all relevant data inside of UBI.
UBI would then be used to handle bad block management. As the vendor
ATF + uboot do not read or interact with the UBI region, we would avoid
unwanted remaps from BMT/BBT.
This commit introduces support for building such a chainloader, by
packaging u-boot and DTS into a FIT image; to be flashed like a kernel.
Configuration for the Gemtek W1700K is provided as an example of how the
chainloader is used.
[1] https://github.com/openwrt/openwrt/pull/17869#discussion_r2836066746
[2] https://github.com/openwrt/openwrt/pull/17869#discussion_r2838395671
Signed-off-by: Kenneth Kasilag <kenneth@kasilag.me>
---
configs/an7581_w1700k_defconfig | 107 ++++++++++
defenvs/an7581_w1700k_env | 21 ++
dts/upstream/src/arm64/airoha/an7581-w1700k-ubi.dts | 87 +++++
3 files changed, 215 insertions(+), 0 deletions(-)
create mode 100644 configs/an7581_w1700k_defconfig
create mode 100644 defenvs/an7581_w1700k_env
create mode 100644 dts/upstream/src/arm64/airoha/an7581-w1700k-ubi.dts
--- /dev/null
+++ b/configs/an7581_w1700k_defconfig
@@ -0,0 +1,107 @@
+CONFIG_ARM=y
+CONFIG_ARCH_AIROHA=y
+CONFIG_AUTOBOOT_KEYED=y
+CONFIG_AUTOBOOT_MENU_SHOW=y
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_TARGET_AN7581=y
+CONFIG_TEXT_BASE=0x81E00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x4000
+CONFIG_ENV_OFFSET=0x7c000
+CONFIG_DM_GPIO=y
+CONFIG_DEFAULT_DEVICE_TREE="airoha/an7581-w1700k-ubi"
+CONFIG_SYS_LOAD_ADDR=0x81800000
+CONFIG_BUILD_TARGET="u-boot.bin"
+# CONFIG_EFI_LOADER is not set
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_BOOTDELAY=30
+CONFIG_DEFAULT_FDT_FILE="an7581-w1700k-ubi"
+CONFIG_SYS_PBSIZE=1049
+CONFIG_SYS_CONSOLE_IS_IN_ENV=y
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_PROMPT="U-Boot> "
+CONFIG_SYS_MAXARGS=8
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTMENU=y
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+CONFIG_CMD_BIND=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_SF_TEST=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_PING=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_CMD_LOG=y
+CONFIG_OF_UPSTREAM=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_MMC=y
+# CONFIG_ENV_IS_IN_MTD is not set
+CONFIG_ENV_RELOC_GD_ENV_ADDR=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_SYS_RX_ETH_BUFFER=8
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_DMA=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_MMC_MTK=y
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_ISSI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_AIROHA_ETH=y
+CONFIG_DM_MDIO=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_MDIO=y
+CONFIG_PHY=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_RAM=y
+CONFIG_DM_SERIAL=y
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_AIROHA_SNFI_SPI=y
+CONFIG_CMD_UBI=y
+# CONFIG_CMD_UBI_RENAME is not set
+CONFIG_CMD_UBIFS=y
+CONFIG_ENV_IS_IN_UBI=y
+CONFIG_ENV_REDUNDANT=y
+CONFIG_ENV_UBI_PART="ubi"
+CONFIG_ENV_UBI_VOLUME="ubootenv"
+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2"
+CONFIG_ENV_UBI_VID_OFFSET=0
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_MODULE=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_LIMIT=20
+# CONFIG_MTD_UBI_FASTMAP is not set
+CONFIG_UBI_BLOCK=y
+# CONFIG_UBIFS_SILENCE_MSG is not set
+# CONFIG_UBIFS_SILENCE_DEBUG_DUMP is not set
+CONFIG_ENV_USE_DEFAULT_ENV_TEXT_FILE=y
+CONFIG_ENV_DEFAULT_ENV_TEXT_FILE="defenvs/an7581_w1700k_env"
+CONFIG_SHA512=y
--- /dev/null
+++ b/defenvs/an7581_w1700k_env
@@ -0,0 +1,27 @@
+loadaddr=0x81800000
+initaddr=0x89000000
+ipaddr=192.168.1.1
+serverip=192.168.1.10
+bootfile=immortalwrt-airoha-an7581-gemtek_w1700k-ubi-initramfs-recovery.itb
+installfile=immortalwrt-airoha-an7581-gemtek_w1700k-ubi-initramfs-installer.itb
+bootled_pwr=status:red
+bootled_rec=status:blue
+boot_ubi=ubi part ubi && run boot_production ; run boot_recovery
+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off
+boot_recovery=led $bootled_rec on ; run ubi_read_recovery ; bootm $initaddr#$bootconf ; led $bootled_rec off
+boot_tftp=tftpboot $initaddr $bootfile && bootm $initaddr#$bootconf
+boot_installer=tftpboot $initaddr $installfile && bootm $initaddr#$bootconf
+bootconf=config-1
+bootcmd=boot_ubi
+bootdelay=3
+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60
+bootmenu_default=0
+bootmenu_delay=3
+bootmenu_title= 34m( ( ( mOpenWrt34m ) ) )
+bootmenu_0=Run default boot command.=run boot_production
+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return
+bootmenu_2=Boot recovery system from flash.=run boot_recovery ; run bootmenu_confirm_return
+bootmenu_3=Boot installer via TFTP.=run boot_installer ; run bootmenu_confirm_return
+bootmenu_4=Reboot.=reset
+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr
+ubi_read_recovery=ubi check recovery && ubi read $initaddr recovery
--- /dev/null
+++ b/dts/upstream/src/arm64/airoha/an7581-w1700k-ubi.dts
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/dts-v1/;
+
+/* Bootloader installs ATF here */
+/memreserve/ 0x80000000 0x200000;
+
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "en7581.dtsi"
+
+/ {
+ model = "Gemtek W1700K (UBI)";
+ compatible = "gemtek,w1700k-ubi", "airoha,an7581", "airoha,en7581";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ linux,usable-memory-range = <0x0 0x80200000 0x0 0x7fe00000>;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x0 0x80000000 0x2 0x00000000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ key-restart {
+ label = "reset";
+ gpios = <&en7581_pinctrl 0 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ led_status_green {
+ label = "status:green";
+ gpios = <&en7581_pinctrl 17 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led_status_blue {
+ label = "status:blue";
+ gpios = <&en7581_pinctrl 19 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led_status_red {
+ label = "status:red";
+ gpios = <&en7581_pinctrl 29 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led_status_white {
+ label = "status:white";
+ gpios = <&en7581_pinctrl 20 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+ };
+};
+
+&snfi {
+ status = "okay";
+};
+
+&spi_nand {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ vendor@0 {
+ label = "vendor";
+ reg = <0x00000000 0x00600000>;
+ read-only;
+ };
+
+ chainloader@600000 {
+ label = "chainloader";
+ reg = <0x00600000 0x00100000>;
+ read-only;
+ };
+
+ ubi@700000 {
+ label = "ubi";
+ reg = <0x00700000 0x1f700000>;
+ };
+
+ /* reserved for bad block table */
+ reserved_bmt@1fe00000 {
+ label = "reserved_bmt";
+ reg = <0x1fe00000 0x00200000>;
+ read-only;
+ };
+ };
+};
+
+&en7581_pinctrl {
+ gpio-ranges = <&en7581_pinctrl 0 13 47>;
+
+ pcie0_rst_pins: pcie0-rst-pins {
+ conf {
+ pins = "pcie_reset0";
+ drive-open-drain = <1>;
+ };
+ };
+};
+
+&pcie0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie0_rst_pins>;
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&eth {
+ status = "okay";
+};
+
+&gdm1 {
+ status = "okay";
+};
+20 -7
View File
@@ -10,11 +10,11 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_SOURCE_URL:=https://github.com/chunkeey/FritzBox-4040-UBOOT
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=9d89013f9cc963eca25856c61fa066091d35f8de
PKG_SOURCE_DATE:=2022-05-01
PKG_MIRROR_HASH:=4e8106a7877ae6aa8da44bf95401b860d11f7d51417cc5a61ce59a353d4ee866
PKG_SOURCE_VERSION:=6909090cb82db96f8ef0cd211ca91e87d69a07fc
PKG_SOURCE_DATE:=2026-03-04
PKG_MIRROR_HASH:=741da058f24e559befff1f2d28d057dbfe9b3a6af67e60191cbefdbacc9143bb
PKG_RELEASE:=5
PKG_RELEASE:=1
include $(INCLUDE_DIR)/u-boot.mk
include $(INCLUDE_DIR)/package.mk
@@ -51,6 +51,12 @@ define U-Boot/fritz7530
BUILD_DEVICES:=avm_fritzbox-7530
endef
define U-Boot/huawei_ap4050dn
NAME:=Huawei AP4050DN
BUILD_DEVICES:=huawei_ap4050dn
UBOOT_IMAGE:=uImage
endef
UBOOT_CONFIGURE_VARS += USE_PRIVATE_LIBGCC=yes
UBOOT_MAKE_FLAGS = USE_PRIVATE_LIBGCC=yes
export DTC
@@ -64,7 +70,14 @@ endef
define Build/Compile
$(Build/Compile/U-Boot)
(cd $(PKG_BUILD_DIR); ./fritz/fritzcreator.sh $(UBOOT_BOARD);)
@( \
cd $(PKG_BUILD_DIR) ; \
if [ "$(UBOOT_BOARD)" = "huawei_ap4050dn" ]; then \
./huawei/huaweicreator.sh $(UBOOT_BOARD) ; \
else \
./fritz/fritzcreator.sh $(UBOOT_BOARD) ; \
fi \
)
endef
define Build/InstallDev
@@ -74,9 +87,9 @@ endef
define Package/u-boot/install
$(Package/u-boot/install/default)
$(INSTALL_BIN) $(PKG_BUILD_DIR)/upload-to-f4040.sh $(1)/
$(if $(filter fritz%,$(BUILD_VARIANT)),$(INSTALL_BIN) $(PKG_BUILD_DIR)/upload-to-f4040.sh $(1)/)
endef
UBOOT_TARGETS := fritz1200 fritz3000 fritz4040 fritz7520 fritz7530
UBOOT_TARGETS := fritz1200 fritz3000 fritz4040 fritz7520 fritz7530 huawei_ap4050dn
$(eval $(call BuildPackage/U-Boot))
+5 -3
View File
@@ -6,9 +6,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/firmware/qca-wireless.git
PKG_SOURCE_DATE:=2026-02-17
PKG_SOURCE_VERSION:=4b7ccdeadfc0eb65c5459234a6d17432052f47f2
PKG_MIRROR_HASH:=80f6f8f5692dcf2ffa4f64d45b96aeb93be3c8d438cfba6d47236d2f0360181c
PKG_SOURCE_DATE:=2026-03-07
PKG_SOURCE_VERSION:=beaf4667b9be6413c6d30994ba38475d77a5ae06
PKG_MIRROR_HASH:=b3b3732aeca7ea587b259953909674bd6cff9ce659b94f140fa3186854c4b521
PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
@@ -45,6 +45,7 @@ ALLWIFIBOARDS:= \
glinet_gl-ax1800 \
glinet_gl-axt1800 \
glinet_gl-b3000 \
huawei_ap4050dn \
ignitenet_ss-w2-ac2600 \
iodata_wn-dax3000gr \
jdcloud_re-cs-02 \
@@ -237,6 +238,7 @@ $(eval $(call generate-ipq-wifi-package,elecom_wrc-x3000gs2,ELECOM WRC-X3000GS2)
$(eval $(call generate-ipq-wifi-package,glinet_gl-ax1800,GL.iNet GL-AX1800))
$(eval $(call generate-ipq-wifi-package,glinet_gl-axt1800,GL.iNet GL-AXT1800))
$(eval $(call generate-ipq-wifi-package,glinet_gl-b3000,GL.iNet GL-B3000))
$(eval $(call generate-ipq-wifi-package,huawei_ap4050dn,Huawei AP4050DN))
$(eval $(call generate-ipq-wifi-package,ignitenet_ss-w2-ac2600,Ignitenet SS-W2-AC2600))
$(eval $(call generate-ipq-wifi-package,iodata_wn-dax3000gr,I-O DATA WN-DAX3000GR))
$(eval $(call generate-ipq-wifi-package,jdcloud_re-cs-02,JDCloud RE-CS-02))
+16 -16
View File
@@ -40,22 +40,6 @@ endef
$(eval $(call KernelPackage,gpio-beeper))
define KernelPackage/gpio-cascade
SUBMENU:=$(GPIO_MENU)
TITLE:=Generic GPIO cascade
KCONFIG:=CONFIG_GPIO_CASCADE
DEPENDS:=@GPIO_SUPPORT +kmod-mux-core
FILES:=$(LINUX_DIR)/drivers/gpio/gpio-cascade.ko
AUTOLOAD:=$(call AutoLoad,29,gpio-cascade,1)
endef
define KernelPackage/gpio-cascade/description
Kernel module for Generic GPIO cascade
endef
$(eval $(call KernelPackage,gpio-cascade))
define KernelPackage/gpio-f7188x
SUBMENU:=$(GPIO_MENU)
TITLE:=Fintek F718xx/F818xx GPIO Support
@@ -90,6 +74,22 @@ endef
$(eval $(call KernelPackage,gpio-it87))
define KernelPackage/gpio-line-mux
SUBMENU:=$(GPIO_MENU)
TITLE:=Virtual GPIO line multiplexer
KCONFIG:=CONFIG_GPIO_LINE_MUX
DEPENDS:=@GPIO_SUPPORT +kmod-mux-core
FILES:=$(LINUX_DIR)/drivers/gpio/gpio-line-mux.ko
AUTOLOAD:=$(call AutoLoad,29,gpio-line-mux,1)
endef
define KernelPackage/gpio-line-mux/description
Kernel module for Virtual GPIO line multiplexer
endef
$(eval $(call KernelPackage,gpio-line-mux))
define KernelPackage/gpio-nxp-74hc164
SUBMENU:=$(GPIO_MENU)
TITLE:=NXP 74HC164 GPIO expander support
+19
View File
@@ -390,6 +390,25 @@ endef
$(eval $(call KernelPackage,iio-ccs811))
define KernelPackage/iio-richtek-rtq6056
TITLE:=Richtek RTQ6056 Current and Power Monitor ADC
DEPENDS:=+kmod-i2c-core +kmod-regmap-i2c +kmod-industrialio-triggered-buffer
KCONFIG:= CONFIG_RICHTEK_RTQ6056
FILES:=$(LINUX_DIR)/drivers/iio/adc/rtq6056.ko
AUTOLOAD:=$(call AutoProbe,rtq6056)
$(call AddDepends/iio)
endef
define KernelPackage/iio-richtek-rtq6056/description
Support for Richtek RTQ6056 Current and Power Monitor ADC.
RTQ6056 is a high accuracy current-sense monitor with I2C and SMBus
compatible interface, and the device provides full information for
system by reading out the load current and power.
endef
$(eval $(call KernelPackage,iio-richtek-rtq6056))
define KernelPackage/iio-si7020
DEPENDS:=+kmod-i2c-core
TITLE:=Silicon Labs Si7020 sensor
@@ -13,7 +13,7 @@ Signed-off-by: Paweł Owoc <frut3k7@gmail.com>
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -2682,7 +2682,7 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(s
@@ -2688,7 +2688,7 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(s
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
cmd->vdev_id = vdev_id;
@@ -0,0 +1,91 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ruslan Isaev <legale.legale@gmail.com>
Date: Sun, 1 Mar 2026 00:00:00 +0000
Subject: [PATCH] wifi: ath11k: ipq807x; ipq60xx: fix monitor rx frame length (+8 tail)
OpenWrt issue:
https://github.com/openwrt/openwrt/issues/16183
Problem summary:
On qualcommax (ipq60xx/ipq807x) with ath11k, monitor-mode captures contain
frames that are consistently longer than expected by 8 bytes.
The symptom is visible in pcap/radiotap captures, and Wireshark parsing
becomes correct after manually cutting these 8 bytes from captured frames.
This patch:
- Remove merge-stage FCS/tail manipulations in ath11k_dp_rx_mon_merg_msdus().
- add length fix in ath11k_dp_rx_mon_deliver(), trim 8 bytes right
before radiotap update and delivery to mac80211.
This targets monitor capture length correctness only and keeps the fix scoped
to the monitor RX delivery path.
Index: backports-6.18.7/drivers/net/wireless/ath/ath11k/dp_rx.c
===================================================================
--- backports-6.18.7.orig/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ backports-6.18.7/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -4931,8 +4931,13 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11
}
prev_buf->next = NULL;
+ /* REMOVED: skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN);
+ * Older code trimmed HAL_RX_FCS_LEN here from prev_buf.
+ * That only affects the last MSDU in the chain.
+ * Length correction is now done in
+ * ath11k_dp_rx_mon_deliver() for every delivered monitor skb.
+ */
- skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN);
} else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) {
u8 qos_pkt = 0;
@@ -4958,10 +4963,13 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11
prev_buf = msdu;
msdu = msdu->next;
}
- dest = skb_put(prev_buf, HAL_RX_FCS_LEN);
- if (!dest)
- goto err_merge_fail;
-
+ /* REMOVED: skb_put(prev_buf, HAL_RX_FCS_LEN)
+ * Older code did skb_put(), effectively
+ * extending the payload tail from merge stage for the last MSDU.
+ * This is removed so merge path does not mutate capture length.
+ * We keep a single length-fix point in monitor deliver path
+ * (trim 8 bytes) right before mac80211 hand-off.
+ */
ath11k_dbg(ab, ATH11K_DBG_DATA,
"mpdu_buf %p mpdu_buf->len %u",
prev_buf, prev_buf->len);
@@ -5086,12 +5094,27 @@ static int ath11k_dp_rx_mon_deliver(stru
header = mon_skb;
- rxs->flag = 0;
+ /* Do not clear rxs->flag here to preserve FCS presence information
+ * set during MSDU merge/trim.
+ */
+ rxs->flag |= RX_FLAG_ONLY_MONITOR;
if (fcs_err)
- rxs->flag = RX_FLAG_FAILED_FCS_CRC;
+ rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
do {
+ /* HW monitor path on ipq60xx/ipq807x may append FCS + 4-byte tail.
+ * Force trim 8 bytes right before delivery to mac80211 so
+ * userspace capture length reflects actual 802.11 frame size.
+ */
+ if (mon_skb->len > (FCS_LEN * 2)) {
+ u32 old_len = mon_skb->len;
+
+ skb_trim(mon_skb, old_len - (FCS_LEN * 2));
+ ath11k_warn(ar->ab, "%s:%d DELIVER trim8 len %u -> %u\n",
+ __func__, __LINE__, old_len, mon_skb->len);
+ }
+
skb_next = mon_skb->next;
if (!skb_next)
rxs->flag &= ~RX_FLAG_AMSDU_MORE;
@@ -1,38 +0,0 @@
--- a/drivers/net/wireless/ath/ath5k/initvals.c
+++ b/drivers/net/wireless/ath/ath5k/initvals.c
@@ -62,8 +62,14 @@ static const struct ath5k_ini ar5210_ini
{ AR5K_IMR, 0 },
{ AR5K_IER, AR5K_IER_DISABLE },
{ AR5K_BSR, 0, AR5K_INI_READ },
+#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79)
{ AR5K_TXCFG, AR5K_DMASIZE_128B },
{ AR5K_RXCFG, AR5K_DMASIZE_128B },
+#else
+ /* WAR for AR71xx PCI bug */
+ { AR5K_TXCFG, AR5K_DMASIZE_128B },
+ { AR5K_RXCFG, AR5K_DMASIZE_4B },
+#endif
{ AR5K_CFG, AR5K_INIT_CFG },
{ AR5K_TOPS, 8 },
{ AR5K_RXNOFRM, 8 },
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -854,10 +854,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah)
* guess we can tweak it and see how it goes ;-)
*/
if (ah->ah_version != AR5K_AR5210) {
+#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79)
AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
+#else
+ /* WAR for AR71xx PCI bug */
+ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+ AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+ AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_4B);
+#endif
}
/* Pre-enable interrupts on 5211/5212*/
@@ -10,21 +10,22 @@
#else
static inline void ath_init_leds(struct ath_softc *sc)
{
@@ -980,6 +983,13 @@ void ath_ant_comb_scan(struct ath_softc
@@ -980,6 +983,14 @@ void ath_ant_comb_scan(struct ath_softc
#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */
+struct ath_led {
+ struct list_head list;
+ struct ath_softc *sc;
+ const struct gpio_led *gpio;
+ struct gpio_led gpio;
+ struct led_classdev cdev;
+ char name[];
+};
+
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
@@ -1035,9 +1045,8 @@ struct ath_softc {
@@ -1035,9 +1046,8 @@ struct ath_softc {
spinlock_t chan_lock;
#ifdef CPTCFG_MAC80211_LEDS
@@ -38,7 +39,7 @@
#ifdef CPTCFG_ATH9K_DEBUGFS
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -39,61 +39,111 @@ static void ath_fill_led_pin(struct ath_
@@ -39,61 +39,112 @@ static void ath_fill_led_pin(struct ath_
else
ah->led_pin = ATH_LED_PIN_DEF;
}
@@ -49,16 +50,17 @@
+{
+ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
+ struct ath_softc *sc = led->sc;
+ const struct gpio_led *gpio = &led->gpio;
+
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
+ (brightness != LED_OFF) ^ led->gpio->active_low);
+ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio,
+ (brightness != LED_OFF) ^ gpio->active_low);
+ ath9k_ps_restore(sc);
+}
+
+static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
+{
+ const struct gpio_led *gpio = led->gpio;
+ const struct gpio_led *gpio = &led->gpio;
+ int ret;
+
+ led->cdev.name = gpio->name;
@@ -94,30 +96,28 @@
- u32 val = (brightness == LED_OFF);
+ struct ath_led *led;
+ struct gpio_led *gpio;
+ char *_name;
+ int ret;
- if (sc->sc_ah->config.led_active_high)
- val = !val;
+ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
+ GFP_KERNEL);
+ led = kzalloc(struct_size(led, name, strlen(name) + 1), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ led->gpio = gpio = (struct gpio_led *) (led + 1);
+ _name = (char *) (led->gpio + 1);
+ strcpy(led->name, name);
+
+ strcpy(_name, name);
+ gpio->name = _name;
+ gpio = &led->gpio;
+ gpio->name = led->name;
+ gpio->gpio = gpio_num;
+ gpio->active_low = active_low;
+ gpio->default_trigger = trigger;
+
+ ret = ath_add_led(sc, led);
+ if (unlikely(ret < 0))
+ kfree(led);
+ if (likely(ret >= 0))
+ return ret;
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val);
+ kfree(led);
+ return ret;
}
@@ -126,6 +126,7 @@
- if (!sc->led_registered)
- return;
+ struct ath_led *led;
+ struct gpio_led *gpio;
- ath_led_brightness(&sc->led_cdev, LED_OFF);
- led_classdev_unregister(&sc->led_cdev);
@@ -136,7 +137,8 @@
+ list_del(&led->list);
+ ath_led_brightness(&led->cdev, LED_OFF);
+ led_classdev_unregister(&led->cdev);
+ ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio);
+ gpio = &led->gpio;
+ ath9k_hw_gpio_free(sc->sc_ah, gpio->gpio);
+ kfree(led);
+ }
}
@@ -13,7 +13,7 @@ Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -73,8 +73,11 @@ static int ath_add_led(struct ath_softc
@@ -74,8 +74,11 @@ static int ath_add_led(struct ath_softc
ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
@@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#include "common.h"
#include "debug.h"
@@ -1047,6 +1049,10 @@ struct ath_softc {
@@ -1048,6 +1050,10 @@ struct ath_softc {
#ifdef CPTCFG_MAC80211_LEDS
const char *led_default_trigger;
struct list_head leds;
@@ -157,7 +157,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static void ath_fill_led_pin(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
@@ -79,6 +189,12 @@ static int ath_add_led(struct ath_softc
@@ -80,6 +190,12 @@ static int ath_add_led(struct ath_softc
else
ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
@@ -170,7 +170,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return 0;
}
@@ -117,16 +233,23 @@ void ath_deinit_leds(struct ath_softc *s
@@ -117,6 +233,11 @@ void ath_deinit_leds(struct ath_softc *s
while (!list_empty(&sc->leds)) {
led = list_first_entry(&sc->leds, struct ath_led, list);
@@ -182,27 +182,20 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
list_del(&led->list);
ath_led_brightness(&led->cdev, LED_OFF);
led_classdev_unregister(&led->cdev);
ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio);
@@ -124,6 +245,7 @@ void ath_deinit_leds(struct ath_softc *s
ath9k_hw_gpio_free(sc->sc_ah, gpio->gpio);
kfree(led);
}
+ ath9k_unregister_gpio_chip(sc);
}
void ath_init_leds(struct ath_softc *sc)
{
+ struct device_node *np = sc->dev->of_node;
char led_name[32];
const char *trigger;
@@ -135,6 +258,15 @@ void ath_init_leds(struct ath_softc *sc)
@@ -136,6 +258,12 @@ void ath_init_leds(struct ath_softc *sc)
if (AR_SREV_9100(sc->sc_ah))
return;
+ if (!np)
+ ath9k_register_gpio_chip(sc);
+
+ /* setup gpio controller only if requested and skip the led_pin setup */
+ if (of_property_read_bool(np, "gpio-controller")) {
+ if (device_property_present(sc->dev, "gpio-controller")) {
+ ath9k_register_gpio_chip(sc);
+ return;
+ }
@@ -0,0 +1,39 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 5 Mar 2026 17:04:11 +0000
Subject: [PATCH] mac80211: fix crash in ieee80211_chan_bw_change for AP_VLAN
stations
ieee80211_chan_bw_change() iterates all stations and accesses
link->reserved.oper via sta->sdata->link[link_id]. For stations on
AP_VLAN interfaces (e.g. 4addr WDS clients), sta->sdata points to
the VLAN sdata, whose link never participates in chanctx reservations.
This leaves link->reserved.oper zero-initialized with chan == NULL,
causing a NULL pointer dereference in __ieee80211_sta_cap_rx_bw()
when accessing chandef->chan->band during CSA.
Resolve the VLAN sdata to its parent AP sdata using get_bss_sdata()
before accessing link data.
Cc: stable@vger.kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -441,13 +441,15 @@ static void ieee80211_chan_bw_change(str
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list,
list) {
- struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_sub_if_data *sdata;
enum ieee80211_sta_rx_bandwidth new_sta_bw;
unsigned int link_id;
if (!ieee80211_sdata_running(sta->sdata))
continue;
+ sdata = get_bss_sdata(sta->sdata);
+
for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
struct ieee80211_link_data *link =
rcu_dereference(sdata->link[link_id]);
@@ -48,7 +48,7 @@
if (sdata->wdev.links[link_id].cac_started)
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -644,10 +644,11 @@ ieee80211_find_chanctx(struct ieee80211_
@@ -646,10 +646,11 @@ ieee80211_find_chanctx(struct ieee80211_
return NULL;
}
@@ -61,7 +61,7 @@
struct ieee80211_link_data *link;
struct ieee80211_channel *chan;
int radio_idx;
@@ -658,14 +659,25 @@ bool ieee80211_is_radar_required(struct
@@ -660,14 +661,25 @@ bool ieee80211_is_radar_required(struct
return false;
for_each_sdata_link(local, link) {
+20 -3
View File
@@ -8,9 +8,9 @@ PKG_LICENSE_FILES:=
PKG_SOURCE_URL:=https://github.com/openwrt/mt76
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2026-03-01
PKG_SOURCE_VERSION:=ee84094d71ba6a361d8cd80392ee79fea64462ec
PKG_MIRROR_HASH:=30d9f42e2c5c2583553f384122b4e380f71a3f579d1cda67a2c533485e30ef5d
PKG_SOURCE_DATE:=2026-03-05
PKG_SOURCE_VERSION:=9f95baf93a070692ed922a2fc57ef8bfde801c84
PKG_MIRROR_HASH:=eaca371ec6f8d0f089d098a3f7fc8c5819aea090e05f4f3d9e8a9b2a2d4f2ff8
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_USE_NINJA:=0
@@ -328,6 +328,12 @@ define KernelPackage/mt7996e
AUTOLOAD:=$(call AutoProbe,mt7996e)
endef
define KernelPackage/mt7990-firmware
$(KernelPackage/mt76-default)
TITLE:=MediaTek MT7990 firmware
DEPENDS+=+kmod-mt7996e
endef
define KernelPackage/mt7992-firmware
$(KernelPackage/mt76-default)
TITLE:=MediaTek MT7992 firmware
@@ -665,6 +671,16 @@ define KernelPackage/mt7925-firmware/install
$(1)/lib/firmware/mediatek/mt7925
endef
define KernelPackage/mt7990-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996
cp \
$(PKG_BUILD_DIR)/firmware/mt7996/mt7990_eeprom.bin \
$(PKG_BUILD_DIR)/firmware/mt7996/mt7990_eeprom_2i5i.bin \
$(PKG_BUILD_DIR)/firmware/mt7996/mt7990_rom_patch.bin \
$(PKG_BUILD_DIR)/firmware/mt7996/mt7990_wm.bin \
$(1)/lib/firmware/mediatek/mt7996
endef
define KernelPackage/mt7992-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996
cp \
@@ -769,6 +785,7 @@ $(eval $(call KernelPackage,mt7921e))
$(eval $(call KernelPackage,mt7925u))
$(eval $(call KernelPackage,mt7925e))
$(eval $(call KernelPackage,mt7996e))
$(eval $(call KernelPackage,mt7990-firmware))
$(eval $(call KernelPackage,mt7992-firmware))
$(eval $(call KernelPackage,mt7992-23-firmware))
$(eval $(call KernelPackage,mt7996-firmware-common))
+3 -3
View File
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/omcproxy.git
PKG_MIRROR_HASH:=4e62452e3b5a6df917e07db6e19b09e0fb67bac246b8fc3f9e6a35a12d90894b
PKG_SOURCE_DATE:=2025-10-04
PKG_SOURCE_VERSION:=fc2eac19ea031411ab589cd92d713961549d6a46
PKG_MIRROR_HASH:=41d85cf544e3833df6a605827ab625a4028274ff46aadee13b8644eb25f8edae
PKG_SOURCE_DATE:=2026-03-07
PKG_SOURCE_VERSION:=3abb601ab77f5e914a3203e5d0c8ae7fb1579bae
PKG_MAINTAINER:=Steven Barth <cyrus@openwrt.org>
PKG_LICENSE:=Apache-2.0
+1 -1
View File
@@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=ppp
PKG_VERSION:=2.5.2
PKG_RELEASE:=2
PKG_RELEASE:=3
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/ppp-project/ppp
@@ -0,0 +1,37 @@
From f8d994052e3858848ce11318085e04fe7a1cfb28 Mon Sep 17 00:00:00 2001
From: LGA1150 <9155358+LGA1150@users.noreply.github.com>
Date: Thu, 5 Mar 2026 05:41:30 +0800
Subject: [PATCH] pppd: fix memcpy overlap (#579)
memcpy() with overlapping src and dest buffers is an undefined behavior
in C. In the current code, a ConfRej response is generated by copying
input data in-place, where the dest address is lower than the src.
This happens to work in practice because memcpy() forward-copies data,
matching the behavior of memmove() in this case.
However, if FORTIFY_SOURCE or Address Sanitizer is enabled, memcpy()
will detect the overlap at run time and abort the program.
Replace the memcpy() with memmove() to ensure a well-defined behavior.
Reported-by: Filippo Carletti <filippo.carletti@gmail.com>
Closes: #576
Signed-off-by: Qingfang Deng <dqfext@gmail.com>
---
pppd/pppd-private.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pppd/pppd-private.h b/pppd/pppd-private.h
index 5f841824..29ea940c 100644
--- a/pppd/pppd-private.h
+++ b/pppd/pppd-private.h
@@ -525,7 +525,7 @@ int parse_dotted_ip(char *, u_int32_t *)
#define TIMEOUT(r, f, t) ppp_timeout((r), (f), (t), 0)
#define UNTIMEOUT(r, f) ppp_untimeout((r), (f))
-#define BCOPY(s, d, l) memcpy(d, s, l)
+#define BCOPY(s, d, l) memmove(d, s, l)
#define BZERO(s, n) memset(s, 0, n)
#define BCMP(s1, s2, l) memcmp(s1, s2, l)
@@ -0,0 +1,28 @@
From f691c224e12ee13a1b317a1838d150f1ffef14a1 Mon Sep 17 00:00:00 2001
From: Mateusz Poliwczak <mpoliwczak34@gmail.com>
Date: Wed, 11 Feb 2026 00:40:14 +0100
Subject: [PATCH] Remove MRU limit on PPPoE (#573)
Fixes #331
Signed-off-by: Mateusz Poliwczak <mpoliwczak34@gmail.com>
---
pppd/plugins/pppoe/plugin.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/pppd/plugins/pppoe/plugin.c b/pppd/plugins/pppoe/plugin.c
index b429a2fd..0f672166 100644
--- a/pppd/plugins/pppoe/plugin.c
+++ b/pppd/plugins/pppoe/plugin.c
@@ -446,11 +446,6 @@ void pppoe_check_options(void)
lcp_allowoptions[0].neg_pcompression = 0;
lcp_wantoptions[0].neg_pcompression = 0;
- if (lcp_allowoptions[0].mru > MAX_PPPOE_MTU)
- lcp_allowoptions[0].mru = MAX_PPPOE_MTU;
- if (lcp_wantoptions[0].mru > MAX_PPPOE_MTU)
- lcp_wantoptions[0].mru = MAX_PPPOE_MTU;
-
/* Save configuration */
conn->storedmtu = lcp_allowoptions[0].mru;
conn->storedmru = lcp_wantoptions[0].mru;
+12
View File
@@ -11,6 +11,7 @@ if len(argv) != 2:
exit(1)
output_path = Path(argv[1])
output_dir = output_path.parent
assert getenv("WORK_DIR"), "$WORK_DIR required"
@@ -28,6 +29,12 @@ def get_initial_output(image_info):
return image_info
def add_artifact(artifact, prefix="openwrt-"):
files = list(output_dir.glob(f"{prefix}{artifact}-*"))
if len(files) == 1:
output[artifact] = str(files[0].name)
for json_file in work_dir.glob("*.json"):
image_info = json.loads(json_file.read_text())
@@ -78,6 +85,11 @@ if output:
"release": linux_release,
"vermagic": linux_vermagic,
}
for artifact in "imagebuilder", "sdk", "toolchain":
filename = add_artifact(artifact)
add_artifact("llvm-bpf", prefix="")
output_path.write_text(json.dumps(output, sort_keys=True, separators=(",", ":")))
else:
print("JSON info file script could not find any JSON files for target")
+3 -1
View File
@@ -237,13 +237,14 @@ CONFIG_MTD_SPLIT_FIT_FW=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y
CONFIG_MTD_UBI_NVMEM=y
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MTK_NET_PHYLIB=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NET_AIROHA=y
CONFIG_NET_AIROHA_FLOW_STATS=y
# CONFIG_NET_AIROHA_FLOW_STATS is not set
CONFIG_NET_AIROHA_NPU=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
@@ -395,6 +396,7 @@ CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
CONFIG_UBIFS_FS=y
# CONFIG_UNMAP_KERNEL_AT_EL0 is not set
CONFIG_UIMAGE_FIT_BLK=y
CONFIG_USB_SUPPORT=y
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_VDSO_GETRANDOM=y
@@ -232,6 +232,12 @@
};
};
&npu {
firmware-name = "airoha/en7581_MT7996_npu_rv32.bin",
"airoha/en7581_MT7996_npu_data.bin";
status = "okay";
};
&eth {
status = "okay";
};
+8 -2
View File
@@ -54,6 +54,11 @@
no-map;
reg = <0x0 0x90c00000 0x0 0x6800>;
};
npu_ba: npu-ba@90c06800 {
no-map;
reg = <0x0 0x90c06800 0x0 0x200000>;
};
};
psci {
@@ -855,9 +860,10 @@
<GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
memory-region = <&npu_binary>, <&npu_pkt>, <&npu_txpkt>,
<&npu_txbufid>;
<&npu_txbufid>, <&npu_ba>;
memory-region-names = "binary", "pkt", "tx-pkt",
"tx-bufid";
"tx-bufid", "ba";
status = "disabled";
};
eth: ethernet@1fb50000 {
+27
View File
@@ -12,6 +12,33 @@ define Build/an7581-bl31-uboot
cat $(STAGING_DIR_IMAGE)/an7581_$1-bl31-u-boot.fip >> $@
endef
define Build/an7581-chainloader
$(INSTALL_DIR) $(KDIR)/chainload-fit-$(notdir $@)
@if [ -f "$(STAGING_DIR_IMAGE)/an7581_$1-u-boot.bin.lzma" ]; then \
KERNEL="$(STAGING_DIR_IMAGE)/an7581_$1-u-boot.bin.lzma"; \
COMP="lzma"; \
else \
KERNEL="$(STAGING_DIR_IMAGE)/an7581_$1-u-boot.bin"; \
COMP="none"; \
fi; \
$(TOPDIR)/scripts/mkits.sh \
-D $(DEVICE_NAME) \
-o $(KDIR)/chainload-fit-$(notdir $@)/u-boot.its \
-k $$KERNEL \
-C $$COMP \
-a 0x80200000 -e 0x80200000 \
-c conf-uboot \
-A arm64 -v u-boot \
-d $(STAGING_DIR_IMAGE)/an7581_$1-u-boot.dtb \
-s 0x82000000
PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) \
$(STAGING_DIR_HOST)/bin/mkimage \
-D "-i $(KDIR)/chainload-fit-$(notdir $@)" \
-f $(KDIR)/chainload-fit-$(notdir $@)/u-boot.its \
$(STAGING_DIR_IMAGE)/an7581_$1-chainload-u-boot.itb
cat $(STAGING_DIR_IMAGE)/an7581_$1-chainload-u-boot.itb >> $@
endef
define Device/FitImageLzma
KERNEL_SUFFIX := -uImage.itb
KERNEL = kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
@@ -0,0 +1,34 @@
From 875a59c9a9e584d99d8e9e5aa8435ec9300bfe91 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 8 Jan 2026 16:05:08 +0100
Subject: [PATCH] net: airoha: npu: Init BA memory region if provided via DTS
Initialize NPU Block Ack memory region if reserved via DTS.
Block Ack memory region is used by NPU MT7996 (Eagle) offloading.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20260108-airoha-ba-memory-region-v3-2-bf1814e5dcc4@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/airoha/airoha_npu.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c
index 22f72c14606599..a56b3780bb627c 100644
--- a/drivers/net/ethernet/airoha/airoha_npu.c
+++ b/drivers/net/ethernet/airoha/airoha_npu.c
@@ -519,6 +519,14 @@ static int airoha_npu_wlan_init_memory(struct airoha_npu *npu)
if (err)
return err;
+ if (of_property_match_string(npu->dev->of_node, "memory-region-names",
+ "ba") >= 0) {
+ cmd = WLAN_FUNC_SET_WAIT_DRAM_BA_NODE_ADDR;
+ err = airoha_npu_wlan_set_reserved_memory(npu, 0, "ba", cmd);
+ if (err)
+ return err;
+ }
+
cmd = WLAN_FUNC_SET_WAIT_IS_FORCE_TO_CPU;
return airoha_npu_wlan_msg_send(npu, 0, cmd, &val, sizeof(val),
GFP_KERNEL);
@@ -0,0 +1,121 @@
From 3847173525e307ebcd23bd4863da943ea78b0057 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 20 Jan 2026 11:17:18 +0100
Subject: [PATCH] net: airoha: npu: Add the capability to read firmware names
from dts
Introduce the capability to read the firmware binary names from device-tree
using the firmware-name property if available.
This patch is needed because NPU firmware binaries are board specific since
they depend on the MediaTek WiFi chip used on the board (e.g. MT7996 or
MT7992) and the WiFi chip version info is not available in the NPU driver.
This is a preliminary patch to enable MT76 NPU offloading if the Airoha SoC
is equipped with MT7996 (Eagle) WiFi chipset.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20260120-airoha-npu-firmware-name-v4-2-88999628b4c1@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/airoha/airoha_npu.c | 46 ++++++++++++++++++++----
1 file changed, 40 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c
index a56b3780bb627c..89f22f3f47dc56 100644
--- a/drivers/net/ethernet/airoha/airoha_npu.c
+++ b/drivers/net/ethernet/airoha/airoha_npu.c
@@ -16,6 +16,8 @@
#define NPU_EN7581_FIRMWARE_DATA "airoha/en7581_npu_data.bin"
#define NPU_EN7581_FIRMWARE_RV32 "airoha/en7581_npu_rv32.bin"
+#define NPU_EN7581_7996_FIRMWARE_DATA "airoha/en7581_MT7996_npu_data.bin"
+#define NPU_EN7581_7996_FIRMWARE_RV32 "airoha/en7581_MT7996_npu_rv32.bin"
#define NPU_AN7583_FIRMWARE_DATA "airoha/an7583_npu_data.bin"
#define NPU_AN7583_FIRMWARE_RV32 "airoha/an7583_npu_rv32.bin"
#define NPU_EN7581_FIRMWARE_RV32_MAX_SIZE 0x200000
@@ -195,18 +197,18 @@ static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,
}
static int airoha_npu_load_firmware(struct device *dev, void __iomem *addr,
- const struct airoha_npu_fw *fw_info)
+ const char *fw_name, int fw_max_size)
{
const struct firmware *fw;
int ret;
- ret = request_firmware(&fw, fw_info->name, dev);
+ ret = request_firmware(&fw, fw_name, dev);
if (ret)
return ret == -ENOENT ? -EPROBE_DEFER : ret;
- if (fw->size > fw_info->max_size) {
+ if (fw->size > fw_max_size) {
dev_err(dev, "%s: fw size too overlimit (%zu)\n",
- fw_info->name, fw->size);
+ fw_name, fw->size);
ret = -E2BIG;
goto out;
}
@@ -218,6 +220,28 @@ static int airoha_npu_load_firmware(struct device *dev, void __iomem *addr,
return ret;
}
+static int
+airoha_npu_load_firmware_from_dts(struct device *dev, void __iomem *addr,
+ void __iomem *base)
+{
+ const char *fw_names[2];
+ int ret;
+
+ ret = of_property_read_string_array(dev->of_node, "firmware-name",
+ fw_names, ARRAY_SIZE(fw_names));
+ if (ret != ARRAY_SIZE(fw_names))
+ return -EINVAL;
+
+ ret = airoha_npu_load_firmware(dev, addr, fw_names[0],
+ NPU_EN7581_FIRMWARE_RV32_MAX_SIZE);
+ if (ret)
+ return ret;
+
+ return airoha_npu_load_firmware(dev, base + REG_NPU_LOCAL_SRAM,
+ fw_names[1],
+ NPU_EN7581_FIRMWARE_DATA_MAX_SIZE);
+}
+
static int airoha_npu_run_firmware(struct device *dev, void __iomem *base,
struct resource *res)
{
@@ -233,14 +257,22 @@ static int airoha_npu_run_firmware(struct device *dev, void __iomem *base,
if (IS_ERR(addr))
return PTR_ERR(addr);
+ /* Try to load firmware images using the firmware names provided via
+ * dts if available.
+ */
+ if (of_find_property(dev->of_node, "firmware-name", NULL))
+ return airoha_npu_load_firmware_from_dts(dev, addr, base);
+
/* Load rv32 npu firmware */
- ret = airoha_npu_load_firmware(dev, addr, &soc->fw_rv32);
+ ret = airoha_npu_load_firmware(dev, addr, soc->fw_rv32.name,
+ soc->fw_rv32.max_size);
if (ret)
return ret;
/* Load data npu firmware */
return airoha_npu_load_firmware(dev, base + REG_NPU_LOCAL_SRAM,
- &soc->fw_data);
+ soc->fw_data.name,
+ soc->fw_data.max_size);
}
static irqreturn_t airoha_npu_mbox_handler(int irq, void *npu_instance)
@@ -790,6 +822,8 @@ module_platform_driver(airoha_npu_driver);
MODULE_FIRMWARE(NPU_EN7581_FIRMWARE_DATA);
MODULE_FIRMWARE(NPU_EN7581_FIRMWARE_RV32);
+MODULE_FIRMWARE(NPU_EN7581_7996_FIRMWARE_DATA);
+MODULE_FIRMWARE(NPU_EN7581_7996_FIRMWARE_RV32);
MODULE_FIRMWARE(NPU_AN7583_FIRMWARE_DATA);
MODULE_FIRMWARE(NPU_AN7583_FIRMWARE_RV32);
MODULE_LICENSE("GPL");
@@ -24,25 +24,27 @@
};
gpio2: key-mux1 {
compatible = "gpio-cascade";
compatible = "gpio-line-mux";
mux-controls = <&mux>;
gpio-controller;
#gpio-cells = <2>;
// GPIOs used by this node, the mux pin
upstream-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; /* 1y */
muxed-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; /* 1y */
gpio-line-mux-states = <0>, <1>, <2>, <3>;
};
gpio3: key-mux2 {
compatible = "gpio-cascade";
compatible = "gpio-line-mux";
mux-controls = <&mux>;
gpio-controller;
#gpio-cells = <2>;
// GPIOs used by this node, the mux pin
upstream-gpios = <&gpio 14 GPIO_ACTIVE_HIGH>; /* 2y */
muxed-gpios = <&gpio 14 GPIO_ACTIVE_HIGH>; /* 2y */
gpio-line-mux-states = <1>, <2>, <3>;
};
keys {
@@ -80,21 +82,21 @@
usb {
label = "usb";
linux,code = <BTN_2>;
gpios = <&gpio3 1 GPIO_ACTIVE_LOW>;
gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
debounce-interval = <60>;
};
router_auto {
label = "router_auto";
linux,code = <BTN_6>;
gpios = <&gpio3 2 GPIO_ACTIVE_HIGH>;
gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>;
debounce-interval = <60>;
};
movie_on {
label = "movie_on";
linux,code = <BTN_4>;
gpios = <&gpio3 3 GPIO_ACTIVE_HIGH>;
gpios = <&gpio3 2 GPIO_ACTIVE_HIGH>;
debounce-interval = <60>;
};
};
+1 -1
View File
@@ -688,7 +688,7 @@ define Device/buffalo_wzr-hp-g300nh
SOC := ar9132
BUFFALO_PRODUCT := WZR-HP-G300NH
BUFFALO_HWVER := 1
DEVICE_PACKAGES := kmod-gpio-cascade kmod-mux-gpio kmod-usb2 kmod-usb-ledtrig-usbport
DEVICE_PACKAGES := kmod-gpio-line-mux kmod-mux-gpio kmod-usb2 kmod-usb-ledtrig-usbport
BLOCKSIZE := 128k
IMAGE_SIZE := 32128k
SUPPORTED_DEVICES += wzr-hp-g300nh
+7 -14
View File
@@ -1,19 +1,19 @@
include ./common-tp-link.mk
define Device/tplink_rex5x-v1
define Device/tplink_rex5x
$(Device/tplink-safeloader)
SOC := qca9558
BLOCKSIZE := 4k
IMAGE_SIZE := 7680k
KERNEL_SIZE := 6016k
DEVICE_PACKAGES := kmod-ath10k-ct-smallbuffers ath10k-firmware-qca988x-ct
DEVICE_COMPAT_VERSION := 2.0
DEVICE_COMPAT_MESSAGE := Partition layout has changed compared to older versions by utilizing unused flash. \
Upgrade via sysupgrade mechanism (-F) will only work if flashed image still fits to the size of old partition (6016 KiB).
DEVICE_COMPAT_VERSION := 3.0
DEVICE_COMPAT_MESSAGE := Partition layout and blocksize changed. Use sysupgrade -F; image must not exceed 6016 KiB (5.875 MB).
IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | check-size | append-metadata
endef
define Device/tplink_re355-v1
$(Device/tplink_rex5x-v1)
$(Device/tplink_rex5x)
DEVICE_MODEL := RE355
DEVICE_VARIANT := v1
TPLINK_BOARD_ID := RE355
@@ -22,7 +22,7 @@ endef
TARGET_DEVICES += tplink_re355-v1
define Device/tplink_re450-v1
$(Device/tplink_rex5x-v1)
$(Device/tplink_rex5x)
DEVICE_MODEL := RE450
DEVICE_VARIANT := v1
TPLINK_BOARD_ID := RE450
@@ -31,17 +31,10 @@ endef
TARGET_DEVICES += tplink_re450-v1
define Device/tplink_re450-v2
$(Device/tplink-safeloader)
$(Device/tplink_rex5x)
SOC := qca9563
IMAGE_SIZE := 7680k
KERNEL_SIZE := 6016k
DEVICE_MODEL := RE450
DEVICE_VARIANT := v2
DEVICE_PACKAGES := kmod-ath10k-ct-smallbuffers ath10k-firmware-qca988x-ct
DEVICE_COMPAT_VERSION := 2.0
DEVICE_COMPAT_MESSAGE := Partition layout has changed compared to older versions by utilizing unused flash. \
Upgrade via sysupgrade mechanism (-F) will only work if flashed image still fits to the size of old partition (6016 KiB).
IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | check-size | append-metadata
TPLINK_BOARD_ID := RE450-V2
LOADER_TYPE := elf
endef
@@ -55,14 +55,14 @@ Tested-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
depends on ARCH_RENESAS || COMPILE_TEST
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4x
@@ -84,6 +84,7 @@ obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4x
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
+obj-$(CONFIG_GPIO_LATCH_MIKROTIK) += gpio-latch-mikrotik.o
obj-$(CONFIG_GPIO_LINE_MUX) += gpio-line-mux.o
obj-$(CONFIG_GPIO_LJCA) += gpio-ljca.o
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
@@ -138,6 +139,7 @@ obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
@@ -16,7 +16,7 @@ case "$(board_name)" in
tplink,re355-v1|\
tplink,re450-v1|\
tplink,re450-v2)
ucidef_set_compat_version "2.0"
ucidef_set_compat_version "3.0"
;;
esac
@@ -426,7 +426,7 @@ Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+...
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21557,6 +21557,14 @@ T: git git://linuxtv.org/media.git
@@ -21563,6 +21563,14 @@ T: git git://linuxtv.org/media.git
F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
F: drivers/media/i2c/imx415.c
@@ -193,7 +193,7 @@ media: i2c: imx519: Squash fixes
+...
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21565,6 +21565,14 @@ T: git git://linuxtv.org/media_tree.git
@@ -21571,6 +21571,14 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/imx477.yaml
F: drivers/media/i2c/imx477.c
@@ -132,7 +132,7 @@ Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+...
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21562,6 +21562,7 @@ M: Raspberry Pi Kernel Maintenance <kern
@@ -21568,6 +21568,7 @@ M: Raspberry Pi Kernel Maintenance <kern
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
@@ -96,7 +96,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
depends on MFD_JANZ_CMODIO
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_GPIO_EN7523) += gpio-en752
@@ -65,6 +65,7 @@ obj-$(CONFIG_GPIO_EN7523) += gpio-en752
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
@@ -137,7 +137,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+...
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21606,6 +21606,14 @@ T: git git://linuxtv.org/media_tree.git
@@ -21612,6 +21612,14 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/imx519.yaml
F: drivers/media/i2c/imx519.c
@@ -271,7 +271,7 @@ Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+...
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21611,7 +21611,7 @@ M: Raspberry Pi Kernel Maintenance <kern
@@ -21617,7 +21617,7 @@ M: Raspberry Pi Kernel Maintenance <kern
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
@@ -67,7 +67,7 @@ Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+...
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20069,6 +20069,13 @@ S: Supported
@@ -20075,6 +20075,13 @@ S: Supported
F: drivers/iio/light/rohm-bu27008.c
F: drivers/iio/light/rohm-bu27034.c
@@ -94,7 +94,7 @@ Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19362,6 +19362,11 @@ L: linux-edac@vger.kernel.org
@@ -19368,6 +19368,11 @@ L: linux-edac@vger.kernel.org
S: Maintained
F: drivers/ras/amd/fmpm.c
@@ -42,7 +42,7 @@ Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19366,6 +19366,7 @@ RASPBERRY PI RP2040 GPIO BRIDGE DRIVER
@@ -19372,6 +19372,7 @@ RASPBERRY PI RP2040 GPIO BRIDGE DRIVER
M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
S: Maintained
F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
@@ -150,7 +150,7 @@ Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21611,6 +21611,13 @@ F: Documentation/devicetree/bindings/med
@@ -21617,6 +21617,13 @@ F: Documentation/devicetree/bindings/med
F: Documentation/devicetree/bindings/media/i2c/imx477.yaml
F: drivers/media/i2c/imx477.c
@@ -58,7 +58,7 @@ Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21617,6 +21617,7 @@ L: linux-media@vger.kernel.org
@@ -21623,6 +21623,7 @@ L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml
@@ -36,7 +36,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19368,6 +19368,16 @@ S: Maintained
@@ -19374,6 +19374,16 @@ S: Maintained
F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
F: drivers/spi/spi-rp2040-gpio-bridge.c
@@ -0,0 +1,128 @@
From 2a7618ba8698874e9871a8ec5453e0068e94d9e5 Mon Sep 17 00:00:00 2001
From: Jonas Jelonek <jelonek.jonas@gmail.com>
Date: Sat, 27 Dec 2025 18:01:33 +0000
Subject: [PATCH] dt-bindings: gpio: add gpio-line-mux controller
Add dt-schema for a gpio-line-mux controller which exposes virtual
GPIOs for a shared GPIO controlled by a multiplexer, e.g. a gpio-mux.
The gpio-line-mux controller is a gpio-controller, thus has mostly the
same semantics. However, it requires a mux-control to be specified upon
which it will operate.
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20251227180134.1262138-2-jelonek.jonas@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-line-mux.yaml
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/gpio-line-mux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GPIO line mux
+
+maintainers:
+ - Jonas Jelonek <jelonek.jonas@gmail.com>
+
+description: |
+ A GPIO controller to provide virtual GPIOs for a 1-to-many input-only mapping
+ backed by a single shared GPIO and a multiplexer. A simple illustrated
+ example is:
+
+ +----- A
+ IN /
+ <-----o------- B
+ / |\
+ | | +----- C
+ | | \
+ | | +--- D
+ | |
+ M1 M0
+
+ MUX CONTROL
+
+ M1 M0 IN
+ 0 0 A
+ 0 1 B
+ 1 0 C
+ 1 1 D
+
+ This can be used in case a real GPIO is connected to multiple inputs and
+ controlled by a multiplexer, and another subsystem/driver does not work
+ directly with the multiplexer subsystem.
+
+properties:
+ compatible:
+ const: gpio-line-mux
+
+ gpio-controller: true
+
+ "#gpio-cells":
+ const: 2
+
+ gpio-line-mux-states:
+ description: Mux states corresponding to the virtual GPIOs.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+
+ gpio-line-names: true
+
+ mux-controls:
+ maxItems: 1
+ description:
+ Phandle to the multiplexer to control access to the GPIOs.
+
+ ngpios: false
+
+ muxed-gpios:
+ maxItems: 1
+ description:
+ GPIO which is the '1' in 1-to-many and is shared by the virtual GPIOs
+ and controlled via the mux.
+
+required:
+ - compatible
+ - gpio-controller
+ - gpio-line-mux-states
+ - mux-controls
+ - muxed-gpios
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/mux/mux.h>
+
+ sfp_gpio_mux: mux-controller-1 {
+ compatible = "gpio-mux";
+ mux-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>,
+ <&gpio0 1 GPIO_ACTIVE_HIGH>;
+ #mux-control-cells = <0>;
+ idle-state = <MUX_IDLE_AS_IS>;
+ };
+
+ sfp1_gpio: sfp-gpio-1 {
+ compatible = "gpio-line-mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ mux-controls = <&sfp_gpio_mux>;
+ muxed-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+
+ gpio-line-mux-states = <0>, <1>, <3>;
+ };
+
+ sfp1: sfp-p1 {
+ compatible = "sff,sfp";
+
+ i2c-bus = <&sfp1_i2c>;
+ los-gpios = <&sfp1_gpio 0 GPIO_ACTIVE_HIGH>;
+ mod-def0-gpios = <&sfp1_gpio 1 GPIO_ACTIVE_LOW>;
+ tx-fault-gpios = <&sfp1_gpio 2 GPIO_ACTIVE_HIGH>;
+ };
@@ -0,0 +1,209 @@
From 2b03d9a40cd1fea42fd65d2b66df80edc0f374c8 Mon Sep 17 00:00:00 2001
From: Jonas Jelonek <jelonek.jonas@gmail.com>
Date: Sat, 27 Dec 2025 18:01:34 +0000
Subject: [PATCH] gpio: add gpio-line-mux driver
Add a new driver which provides a 1-to-many mapping for a single real
GPIO using a multiplexer. Each virtual GPIO corresponds to a multiplexer
state which, if set for the multiplexer, connects the real GPIO to the
corresponding virtual GPIO.
This can help in various usecases. One practical case is the special
hardware design of the Realtek-based XS1930-10 switch from Zyxel. It
features two SFP+ ports/cages whose signals are wired directly to the
switch SoC. Although Realtek SoCs are short on GPIOs, there are usually
enough the fit the SFP signals without any hacks.
However, Zyxel did some weird design and connected RX_LOS, MOD_ABS and
TX_FAULT of one SFP cage onto a single GPIO line controlled by a
multiplexer (the same for the other SFP cage). The single multiplexer
controls the lines for both SFP and depending on the state, the
designated 'signal GPIO lines' are connected to one of the three SFP
signals.
Because the SFP core/driver doesn't support multiplexer but needs single
GPIOs for each of the signals, this driver fills the gap between both.
It registers a gpio_chip, provides multiple virtual GPIOs and sets the
backing multiplexer accordingly.
Due to several practical issues, this is input-only and doesn't support
IRQs.
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Reviewed-by: Thomas Richard <thomas.richard@bootlin.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20251227180134.1262138-3-jelonek.jonas@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9704,6 +9704,12 @@ S: Maintained
F: Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.yaml
F: drivers/media/rc/gpio-ir-tx.c
+GPIO LINE MUX
+M: Jonas Jelonek <jelonek.jonas@gmail.com>
+S: Maintained
+F: Documentation/devicetree/bindings/gpio/gpio-line-mux.yaml
+F: drivers/gpio/gpio-line-mux.c
+
GPIO MOCKUP DRIVER
M: Bamvor Jian Zhang <bamv2005@gmail.com>
L: linux-gpio@vger.kernel.org
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1866,6 +1866,15 @@ config GPIO_LATCH
Say yes here to enable a driver for GPIO multiplexers based on latches
connected to other GPIOs.
+config GPIO_LINE_MUX
+ tristate "GPIO line mux driver"
+ depends on OF_GPIO
+ select MULTIPLEXER
+ help
+ Say Y here to support the GPIO line mux, which can provide virtual
+ GPIOs backed by a shared real GPIO and a multiplexer in a 1-to-many
+ fashion.
+
config GPIO_MOCKUP
tristate "GPIO Testing Driver (DEPRECATED)"
select IRQ_SIM
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4x
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
+obj-$(CONFIG_GPIO_LINE_MUX) += gpio-line-mux.o
obj-$(CONFIG_GPIO_LJCA) += gpio-ljca.o
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
--- /dev/null
+++ b/drivers/gpio/gpio-line-mux.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPIO line mux which acts as virtual gpiochip and provides a 1-to-many
+ * mapping between virtual GPIOs and a real GPIO + multiplexer.
+ *
+ * Copyright (c) 2025 Jonas Jelonek <jelonek.jonas@gmail.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/mux/consumer.h>
+#include <linux/platform_device.h>
+
+#define MUX_SELECT_DELAY_US 100
+
+struct gpio_lmux {
+ struct gpio_chip gc;
+ struct mux_control *mux;
+ struct gpio_desc *muxed_gpio;
+
+ u32 num_gpio_mux_states;
+ unsigned int gpio_mux_states[] __counted_by(num_gpio_mux_states);
+};
+
+static int gpio_lmux_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpio_lmux *glm = gpiochip_get_data(gc);
+ int ret;
+
+ if (offset > gc->ngpio)
+ return -EINVAL;
+
+ ret = mux_control_select_delay(glm->mux, glm->gpio_mux_states[offset],
+ MUX_SELECT_DELAY_US);
+ if (ret < 0)
+ return ret;
+
+ ret = gpiod_get_raw_value_cansleep(glm->muxed_gpio);
+ mux_control_deselect(glm->mux);
+ return ret;
+}
+
+static int gpio_lmux_gpio_set(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ return -EOPNOTSUPP;
+}
+
+static int gpio_lmux_gpio_get_direction(struct gpio_chip *gc,
+ unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int gpio_lmux_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_lmux *glm;
+ unsigned int ngpio;
+ size_t size;
+ int ret;
+
+ ngpio = device_property_count_u32(dev, "gpio-line-mux-states");
+ if (!ngpio)
+ return -EINVAL;
+
+ size = struct_size(glm, gpio_mux_states, ngpio);
+ glm = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (!glm)
+ return -ENOMEM;
+
+ glm->gc.base = -1;
+ glm->gc.can_sleep = true;
+ glm->gc.fwnode = dev_fwnode(dev);
+ glm->gc.label = dev_name(dev);
+ glm->gc.ngpio = ngpio;
+ glm->gc.owner = THIS_MODULE;
+ glm->gc.parent = dev;
+
+ glm->gc.get = gpio_lmux_gpio_get;
+ glm->gc.set = gpio_lmux_gpio_set;
+ glm->gc.get_direction = gpio_lmux_gpio_get_direction;
+
+ glm->mux = devm_mux_control_get(dev, NULL);
+ if (IS_ERR(glm->mux))
+ return dev_err_probe(dev, PTR_ERR(glm->mux),
+ "could not get mux controller\n");
+
+ glm->muxed_gpio = devm_gpiod_get(dev, "muxed", GPIOD_IN);
+ if (IS_ERR(glm->muxed_gpio))
+ return dev_err_probe(dev, PTR_ERR(glm->muxed_gpio),
+ "could not get muxed-gpio\n");
+
+ glm->num_gpio_mux_states = ngpio;
+ ret = device_property_read_u32_array(dev, "gpio-line-mux-states",
+ &glm->gpio_mux_states[0], ngpio);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not get mux states\n");
+
+ ret = devm_gpiochip_add_data(dev, &glm->gc, glm);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add gpiochip\n");
+
+ return 0;
+}
+
+static const struct of_device_id gpio_lmux_of_match[] = {
+ { .compatible = "gpio-line-mux" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gpio_lmux_of_match);
+
+static struct platform_driver gpio_lmux_driver = {
+ .driver = {
+ .name = "gpio-line-mux",
+ .of_match_table = gpio_lmux_of_match,
+ },
+ .probe = gpio_lmux_probe,
+};
+module_platform_driver(gpio_lmux_driver);
+
+MODULE_AUTHOR("Jonas Jelonek <jelonek.jonas@gmail.com>");
+MODULE_DESCRIPTION("GPIO line mux driver");
+MODULE_LICENSE("GPL");
@@ -0,0 +1,52 @@
From e034e058897a12bc856f8b22d1796964c742f732 Mon Sep 17 00:00:00 2001
From: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Date: Wed, 7 Jan 2026 09:58:33 +0100
Subject: [PATCH] gpio: line-mux: remove bits already handled by GPIO core
GPIO core already handles checking the offset against the number of
GPIOs as well as missing any of the GPIO chip callbacks. Remove the
unnecessary bits.
Also, the offset check was off-by-one as reported by Dan.
Fixes: 2b03d9a40cd1 ("gpio: add gpio-line-mux driver")
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/all/aV4b6GAGz1zyf8Xy@stanley.mountain/
Tested-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Reviewed-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Link: https://lore.kernel.org/r/20260107085833.17338-1-bartosz.golaszewski@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
--- a/drivers/gpio/gpio-line-mux.c
+++ b/drivers/gpio/gpio-line-mux.c
@@ -29,9 +29,6 @@ static int gpio_lmux_gpio_get(struct gpi
struct gpio_lmux *glm = gpiochip_get_data(gc);
int ret;
- if (offset > gc->ngpio)
- return -EINVAL;
-
ret = mux_control_select_delay(glm->mux, glm->gpio_mux_states[offset],
MUX_SELECT_DELAY_US);
if (ret < 0)
@@ -42,12 +39,6 @@ static int gpio_lmux_gpio_get(struct gpi
return ret;
}
-static int gpio_lmux_gpio_set(struct gpio_chip *gc, unsigned int offset,
- int value)
-{
- return -EOPNOTSUPP;
-}
-
static int gpio_lmux_gpio_get_direction(struct gpio_chip *gc,
unsigned int offset)
{
@@ -80,7 +71,6 @@ static int gpio_lmux_probe(struct platfo
glm->gc.parent = dev;
glm->gc.get = gpio_lmux_gpio_get;
- glm->gc.set = gpio_lmux_gpio_set;
glm->gc.get_direction = gpio_lmux_gpio_get_direction;
glm->mux = devm_mux_control_get(dev, NULL);
+1 -1
View File
@@ -2232,7 +2232,6 @@ CONFIG_GPIOLIB_FASTPATH_LIMIT=512
# CONFIG_GPIO_BRCMSTB is not set
# CONFIG_GPIO_BT8XX is not set
# CONFIG_GPIO_CADENCE is not set
# CONFIG_GPIO_CASCADE is not set
# CONFIG_GPIO_CDEV is not set
# CONFIG_GPIO_CDEV_V1 is not set
# CONFIG_GPIO_CS5535 is not set
@@ -2253,6 +2252,7 @@ CONFIG_GPIOLIB_FASTPATH_LIMIT=512
# CONFIG_GPIO_IT87 is not set
# CONFIG_GPIO_LATCH is not set
# CONFIG_GPIO_LOGICVC is not set
# CONFIG_GPIO_LINE_MUX is not set
# CONFIG_GPIO_MAX3191X is not set
# CONFIG_GPIO_MAX7300 is not set
# CONFIG_GPIO_MAX7301 is not set
@@ -36,7 +36,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23671,6 +23671,12 @@ F: Documentation/filesystems/ubifs-authe
@@ -23677,6 +23677,12 @@ F: Documentation/filesystems/ubifs-authe
F: Documentation/filesystems/ubifs.rst
F: fs/ubifs/
@@ -0,0 +1,149 @@
From patchwork Fri Mar 6 12:29:55 2026
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?=
<noltari@gmail.com>
X-Patchwork-Id: 14457090
X-Patchwork-Delegate: kuba@kernel.org
Received: from mail-wr1-f48.google.com (mail-wr1-f48.google.com
[209.85.221.48])
(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))
(No client certificate requested)
by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF3F4386459
for <netdev@vger.kernel.org>; Fri, 6 Mar 2026 12:52:18 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
arc=none smtp.client-ip=209.85.221.48
ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
t=1772801540; cv=none;
b=LVeywxv8ajenPZ8Kr1arieKosbrf60O9l+ouIPKPFNt5btxWDZ59pIU9BfZjv5n9ifEOyUA/UD0phxnG77+oB/k6UCd7DdGQQASZB3NHq5cvmErbgXm0XG3C8BBxVXU5pF7atPS23kBqM9ptxsv3IaeH/fDFcj6k6SH61rGEpuQ=
ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org;
s=arc-20240116; t=1772801540; c=relaxed/simple;
bh=HAy43ssDo0xlUcBDIU7vQZtNnpxG03JPCL6Ldi51ASI=;
h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type;
b=OBk8kI0I91psFRaIxb6nCnAzQlsc7jrXkOPW8lL7cYCosY08yfQDwAlWBFfdFs/VDuVJjD5VEdeQeMt2K4kWGgjLNXhTrRqgs6JNe7PxALDJKvt+kcJ833TRz3hKl2eb2Ft6WnKPf/6hp5Q3qm8+/Q703ixD4sF/0aDNw1BrDY4=
ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
dmarc=pass (p=none dis=none) header.from=gmail.com;
spf=pass smtp.mailfrom=gmail.com;
dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com
header.b=RCEse1HL; arc=none smtp.client-ip=209.85.221.48
Authentication-Results: smtp.subspace.kernel.org;
dmarc=pass (p=none dis=none) header.from=gmail.com
Authentication-Results: smtp.subspace.kernel.org;
spf=pass smtp.mailfrom=gmail.com
Authentication-Results: smtp.subspace.kernel.org;
dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com
header.b="RCEse1HL"
Received: by mail-wr1-f48.google.com with SMTP id
ffacd0b85a97d-439b7c2788dso4008389f8f.1
for <netdev@vger.kernel.org>; Fri, 06 Mar 2026 04:52:18 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1772801537; x=1773406337;
darn=vger.kernel.org;
h=content-transfer-encoding:mime-version:message-id:date:subject:cc
:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=y8B8kg8ACcCsMXy3SgsyRYngVEpIsqkcoCsLOS/nNqQ=;
b=RCEse1HLoUtQApOdbPXFvYItGrEKWhMZ5FH1L4npAxteGeWOhAEAekijg3Ur83ovNu
D7j0Aio5nwazNQz3y4rO88a+svlEbLx5fyxypjkMFUV4PDnOpv7HYjT9Aw1NVdIwO6l+
sTgZ1jssfWdVnLQwQe6naotyBRoBV2AugdTmASE0Okxrsi3juIOafyTCxnp4K0weRpaH
XodiSWNrkHzZSWM6/wl3D42yExGGPiuDybF+9otR/5TaBWNzrcLkSb73hvP6va35kQWK
mnp6OV+L7iHTbxYpTfTm4axD+IZ/Q/dtFxxA6XolA28oMQbRPK0SIHepheSZx4bgl64w
FM4w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1772801537; x=1773406337;
h=content-transfer-encoding:mime-version:message-id:date:subject:cc
:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=y8B8kg8ACcCsMXy3SgsyRYngVEpIsqkcoCsLOS/nNqQ=;
b=KomubXrbvHQI4WbFxBztyfrvNNRRWm7V46yQSwx0bP8PXKIJP38kAYzK+ZKWhmcd7e
LpS7422VcYyLywLRxlevD2YaXsF0CK6e00YpTtixakHxYs/4KxGaU21vfwYV8mRhfu7g
HVmxKvNQ6DTdC7wAIGT6TrcZCK4VCvgCx3z9yC62hQc8C6w+9mDnnGPvXNR74ofvvXdC
eVZjm56layRoEr4PTpR2F33OVSt8+HRikH7eBzIKtQ5n/lEKtmJKDHRaodAaCyFGWMWa
qDVoOR8VI4NIJABfsOT6OqisXLPLf+jkKpGkCY2ioRPRKK9GzW4PgIuNcKvPQilQQkgD
Xlnw==
X-Forwarded-Encrypted: i=1;
AJvYcCVcziiSg1n0cDakmiQXH3869FECP24dcIqrZzs8zKakP+vHT958hnq9Bp0alDnLeVtXgo0B8T4=@vger.kernel.org
X-Gm-Message-State: AOJu0Yx2OF1e3PiuR4Zqpe9qXA6kz6T2CCtro6kv8eL2j4Zh2HCjWywo
/rZTavazOZRoq7zTvc4fGZ/yupjkTT9xRPZCKRkM9pc0UuK/KDSP4pan
X-Gm-Gg: ATEYQzx75s3OlYg8XKMgu042++2+ZPa/CZDw09DYtnwEHHBsuylQF0+eXzcFM166JtP
EMuM6Nq/sGQx2WNTPNEyu1BRGci/SV005CzkExhd1KK52D/nC1c76MBxvAtioaI/+5tgNoyCg8v
ZFRyiqDReKfJ6JHa3YRI213dTzMluN1sZTYNSqlWI1MwW66gaDCf0myU81ehAfiAff34wmxnm8C
PUF0YrLYtgZl1I/ZcYM1npoL3PBOnrhaulSqhbn7S5NaZMkHLrNQm6ns1lof+7Ciju05dQpEcBe
pumVg15Dy+PcSXQSSQt4CULH7bbuJvZ0PHJ7dS+74i/OqFSgxD4E7LCqM5ufHYdbESx0/ERaR/z
CAyT3oTz6S1oMQCUTPevHjHjTbDOWhu74SqyTZETzwGnjZnfrPMa56ebQVRfYgOYW0bbx6j3O2M
v3CSEBiXpdFTdaLuRcqIb56JeDryaHx87SOThqnYP6gMiu7EljKYIhr572Rpgz+UIRkrYyNjL9c
BLmrcmhsXX4hU4X5KocoApkO04w
X-Received: by 2002:a05:600c:8b8b:b0:483:103c:b1ee with SMTP id
5b1f17b1804b1-48526922599mr34173745e9.8.1772801536778;
Fri, 06 Mar 2026 04:52:16 -0800 (PST)
Received: from skynet.lan
(2a02-9142-4581-3c00-0000-0000-0000-0008.red-2a02-914.customerbaf.ipv6.rima-tde.net.
[2a02:9142:4581:3c00::8])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-48527681a3esm76085715e9.4.2026.03.06.04.52.14
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 06 Mar 2026 04:52:15 -0800 (PST)
From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= <noltari@gmail.com>
To: linux@armlinux.org.uk,
andrew@lunn.ch,
hkallweit1@gmail.com,
davem@davemloft.net,
edumazet@google.com,
kuba@kernel.org,
pabeni@redhat.com,
mnhagan88@gmail.com,
netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= <noltari@gmail.com>
Subject: [PATCH net v3] net: sfp: improve Huawei MA5671a fixup
Date: Fri, 6 Mar 2026 13:29:55 +0100
Message-ID: <20260306125139.213637-1-noltari@gmail.com>
X-Mailer: git-send-email 2.47.3
Precedence: bulk
X-Mailing-List: netdev@vger.kernel.org
List-Id: <netdev.vger.kernel.org>
List-Subscribe: <mailto:netdev+subscribe@vger.kernel.org>
List-Unsubscribe: <mailto:netdev+unsubscribe@vger.kernel.org>
MIME-Version: 1.0
X-Patchwork-Delegate: kuba@kernel.org
With the current sfp_fixup_ignore_tx_fault() fixup we ignore the TX_FAULT
signal, but we also need to apply sfp_fixup_ignore_los() in order to be
able to communicate with the module even if the fiber isn't connected for
configuration purposes.
This is needed for all the MA5671a firmwares, excluding the FS modded
firmware.
Fixes: 2069624dac19 ("net: sfp: Add tx-fault workaround for Huawei MA5671A SFP ONT")
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
v3: avoid using a vendor name in the function
v2: rebase on top of net/main instead of linux/master
drivers/net/phy/sfp.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -360,6 +360,12 @@ static void sfp_fixup_ignore_tx_fault(st
sfp->state_ignore_mask |= SFP_F_TX_FAULT;
}
+static void sfp_fixup_ignore_tx_fault_and_los(struct sfp *sfp)
+{
+ sfp_fixup_ignore_tx_fault(sfp);
+ sfp_fixup_ignore_los(sfp);
+}
+
static void sfp_fixup_ignore_hw(struct sfp *sfp, unsigned int mask)
{
sfp->state_hw_mask &= ~mask;
@@ -523,7 +529,7 @@ static const struct sfp_quirk sfp_quirks
// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in
// their EEPROM
SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
- sfp_fixup_ignore_tx_fault),
+ sfp_fixup_ignore_tx_fault_and_los),
// Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report
// 2500MBd NRZ in their EEPROM
@@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14427,7 +14427,9 @@ M: Daniel Golle <daniel@makrotopia.org>
@@ -14432,7 +14432,9 @@ M: Daniel Golle <daniel@makrotopia.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/pcs/pcs-mtk-lynxi.c
@@ -1,217 +0,0 @@
From fc23ea48ba52c24f201fe5ca0132ee1a3de5a70a Mon Sep 17 00:00:00 2001
From: Mauri Sandberg <maukka@ext.kapsi.fi>
Date: Thu, 25 Mar 2021 11:48:05 +0200
Subject: [PATCH 2/2] gpio: gpio-cascade: add generic GPIO cascade
Adds support for building cascades of GPIO lines. That is, it allows
setups when there is one upstream line and multiple cascaded lines, out
of which one can be chosen at a time. The status of the upstream line
can be conveyed to the selected cascaded line or, vice versa, the status
of the cascaded line can be conveyed to the upstream line.
A multiplexer is being used to select, which cascaded GPIO line is being
used at any given time.
At the moment only input direction is supported. In future it should be
possible to add support for output direction, too.
Signed-off-by: Mauri Sandberg <maukka@ext.kapsi.fi>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
v7 -> v8:
- rearrange members in struct gpio_cascade
- cosmetic changes in file header and in one function declaration
- added Reviewed-by tags by Linus and Andy
v6 -> v7:
- In Kconfig add info about module name
- adhere to new convention that allows lines longer than 80 chars
- use dev_probe_err with upstream gpio line too
- refactor for cleaner exit of probe function.
v5 -> v6:
- In Kconfig, remove dependency to OF_GPIO and select only MULTIPLEXER
- refactor code preferring one-liners
- clean up prints, removing them from success-path.
- don't explicitly set gpio_chip.of_node as it's done in the GPIO library
- use devm_gpiochip_add_data instead of gpiochip_add
v4 -> v5:
- renamed gpio-mux-input -> gpio-cascade. refactored code accordingly
here and there and changed to use new bindings and compatible string
- ambigious and vague 'pin' was rename to 'upstream_line'
- dropped Tested-by and Reviewed-by due to changes in bindings
- dropped Reported-by suggested by an automatic bot as it was not really
appropriate to begin with
- functionally it's the same as v4
v3 -> v4:
- Changed author email
- Included Tested-by and Reviewed-by from Drew
v2 -> v3:
- use managed device resources
- update Kconfig description
v1 -> v2:
- removed .owner from platform_driver as per test bot's instruction
- added MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_LICENSE
- added gpio_mux_input_get_direction as it's recommended for all chips
- removed because this is input only chip: gpio_mux_input_set_value
- removed because they are not needed for input/output only chips:
gpio_mux_input_direction_input
gpio_mux_input_direction_output
- fixed typo in an error message
- added info message about successful registration
- removed can_sleep flag as this does not sleep while getting GPIO value
like I2C or SPI do
- Updated description in Kconfig
---
drivers/gpio/Kconfig | 15 +++++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-cascade.c | 117 ++++++++++++++++++++++++++++++++++++
3 files changed, 133 insertions(+)
create mode 100644 drivers/gpio/gpio-cascade.c
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1929,4 +1929,19 @@ config GPIO_VIRTUSER
endmenu
+comment "Other GPIO expanders"
+
+config GPIO_CASCADE
+ tristate "General GPIO cascade"
+ select MULTIPLEXER
+ help
+ Say yes here to enable support for generic GPIO cascade.
+
+ This allows building one-to-many cascades of GPIO lines using
+ different types of multiplexers readily available. At the
+ moment only input lines are supported.
+
+ To build the driver as a module choose 'm' and the resulting module
+ will be called 'gpio-cascade'.
+
endif
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
+obj-$(CONFIG_GPIO_CASCADE) += gpio-cascade.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
obj-$(CONFIG_GPIO_CROS_EC) += gpio-cros-ec.o
--- /dev/null
+++ b/drivers/gpio/gpio-cascade.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * A generic GPIO cascade driver
+ *
+ * Copyright (C) 2021 Mauri Sandberg <maukka@ext.kapsi.fi>
+ *
+ * This allows building cascades of GPIO lines in a manner illustrated
+ * below:
+ *
+ * /|---- Cascaded GPIO line 0
+ * Upstream | |---- Cascaded GPIO line 1
+ * GPIO line ----+ | .
+ * | | .
+ * \|---- Cascaded GPIO line n
+ *
+ * A multiplexer is being used to select, which cascaded line is being
+ * addressed at any given time.
+ *
+ * At the moment only input mode is supported due to lack of means for
+ * testing output functionality. At least theoretically output should be
+ * possible with open drain constructions.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mux/consumer.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+
+struct gpio_cascade {
+ struct gpio_chip gpio_chip;
+ struct device *parent;
+ struct mux_control *mux_control;
+ struct gpio_desc *upstream_line;
+};
+
+static int gpio_cascade_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int gpio_cascade_get_value(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpio_cascade *cas = gpiochip_get_data(gc);
+ int ret;
+
+ ret = mux_control_select(cas->mux_control, offset);
+ if (ret)
+ return ret;
+
+ ret = gpiod_get_value(cas->upstream_line);
+ mux_control_deselect(cas->mux_control);
+ return ret;
+}
+
+static int gpio_cascade_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_cascade *cas;
+ struct mux_control *mc;
+ struct gpio_desc *upstream;
+ struct gpio_chip *gc;
+
+ cas = devm_kzalloc(dev, sizeof(*cas), GFP_KERNEL);
+ if (!cas)
+ return -ENOMEM;
+
+ mc = devm_mux_control_get(dev, NULL);
+ if (IS_ERR(mc))
+ return dev_err_probe(dev, PTR_ERR(mc), "unable to get mux-control\n");
+
+ cas->mux_control = mc;
+ upstream = devm_gpiod_get(dev, "upstream", GPIOD_IN);
+ if (IS_ERR(upstream))
+ return dev_err_probe(dev, PTR_ERR(upstream), "unable to claim upstream GPIO line\n");
+
+ cas->upstream_line = upstream;
+ cas->parent = dev;
+
+ gc = &cas->gpio_chip;
+ gc->get = gpio_cascade_get_value;
+ gc->get_direction = gpio_cascade_get_direction;
+ gc->base = -1;
+ gc->ngpio = mux_control_states(mc);
+ gc->label = dev_name(cas->parent);
+ gc->parent = cas->parent;
+ gc->owner = THIS_MODULE;
+
+ platform_set_drvdata(pdev, cas);
+ return devm_gpiochip_add_data(dev, &cas->gpio_chip, cas);
+}
+
+static const struct of_device_id gpio_cascade_id[] = {
+ { .compatible = "gpio-cascade" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, gpio_cascade_id);
+
+static struct platform_driver gpio_cascade_driver = {
+ .driver = {
+ .name = "gpio-cascade",
+ .of_match_table = gpio_cascade_id,
+ },
+ .probe = gpio_cascade_probe,
+};
+module_platform_driver(gpio_cascade_driver);
+
+MODULE_AUTHOR("Mauri Sandberg <maukka@ext.kapsi.fi>");
+MODULE_DESCRIPTION("Generic GPIO cascade");
+MODULE_LICENSE("GPL");
@@ -57,6 +57,7 @@ ipq40xx_setup_interfaces()
dlink,dap-2610|\
engenius,eap1300|\
extreme-networks,ws-ap3915i|\
huawei,ap4050dn|\
meraki,mr20|\
meraki,mr33|\
meraki,mr70|\
@@ -77,6 +77,10 @@ case "$FIRMWARE" in
caldata_extract "ART" 0x1000 0x2f20
ath10k_patch_mac $(mtd_get_mac_ascii CFG1 RADIOADDR0)
;;
huawei,ap4050dn)
caldata_extract "0:ART" 0x1000 0x2f20
ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 1)
;;
mikrotik,cap-ac|\
mikrotik,hap-ac2|\
mikrotik,hap-ac3|\
@@ -159,6 +163,10 @@ case "$FIRMWARE" in
caldata_extract "ART" 0x5000 0x2f20
ath10k_patch_mac $(mtd_get_mac_ascii CFG1 RADIOADDR1)
;;
huawei,ap4050dn)
caldata_extract "0:ART" 0x5000 0x2f20
ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 2)
;;
mikrotik,cap-ac|\
mikrotik,hap-ac2|\
mikrotik,hap-ac3|\
@@ -167,6 +167,16 @@ platform_do_upgrade() {
CI_ROOTPART="rootfs"
emmc_do_upgrade "$1"
;;
huawei,ap4050dn)
# Store beginning address of the "uboot" partition
# as KernelA address and KernelB address, each to ResultA & ResultB
# This is the address from which the bootloader will try to load the u-boot that we use as loader.
HUAWEI_AP4050DN_LOADADDR="\x00\x00\x70\x00\x00\x00\x70\x00"
echo -n -e $HUAWEI_AP4050DN_LOADADDR | dd of=$(find_mtd_part ResultA) bs=1 seek=$((0x4264)) conv=notrunc
echo -n -e $HUAWEI_AP4050DN_LOADADDR | dd of=$(find_mtd_part ResultA) bs=1 seek=$((0x40264)) conv=notrunc
echo -n -e $HUAWEI_AP4050DN_LOADADDR | dd of=$(find_mtd_part ResultB) bs=1 seek=$((0x4264)) conv=notrunc
default_do_upgrade "$1"
;;
linksys,ea6350v3|\
linksys,ea8300|\
linksys,mr6350|\
+4
View File
@@ -309,6 +309,7 @@ CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_FIT_FW=y
CONFIG_MTD_SPLIT_WRGG_FW=y
CONFIG_MTD_VIRT_CONCAT=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SRCU_NMI_SAFE=y
@@ -323,6 +324,7 @@ CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_INGRESS=y
CONFIG_NET_PTP_CLASSIFY=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NET_XGRESS=y
CONFIG_NLS=y
CONFIG_NO_HZ=y
@@ -353,6 +355,7 @@ CONFIG_PAGE_OFFSET=0xC0000000
CONFIG_PAGE_POOL=y
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y
CONFIG_PCI=y
CONFIG_PCIEAER=y
CONFIG_PCIEPORTBUS=y
@@ -480,6 +483,7 @@ CONFIG_SGL_ALLOC=y
CONFIG_SKB_EXTENSIONS=y
CONFIG_SMP=y
CONFIG_SMP_ON_UP=y
# CONFIG_SM_GCC_7150 is not set
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_SOFTIRQ_ON_OWN_STACK=y
CONFIG_SPARSE_IRQ=y
@@ -0,0 +1,381 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
#include "qcom-ipq4019.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/soc/qcom,tcsr.h>
/ {
model = "Huawei AP4050DN";
compatible = "huawei,ap4050dn", "qcom,ipq40xx";
chosen {
bootargs = "console=ttyMSM0,9600n8";
};
aliases {
ethernet0 = &gmac;
led-boot = &led_function_green;
led-failsafe = &led_function_red;
led-running = &led_function_green;
led-upgrade = &led_function_red;
label-mac-device = &gmac;
};
soc {
rng@22000 {
status = "okay";
};
counter@4a1000 {
compatible = "qcom,qca-gcnt";
reg = <0x4a1000 0x4>;
};
tcsr@1949000 {
compatible = "qcom,tcsr";
reg = <0x1949000 0x100>;
qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
};
ess_tcsr@1953000 {
compatible = "qcom,tcsr";
reg = <0x1953000 0x1000>;
qcom,ess-interface-select = <TCSR_ESS_PSGMII>;
};
tcsr@1957000 {
compatible = "qcom,tcsr";
reg = <0x1957000 0x100>;
qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
};
crypto@8e3a000 {
status = "okay";
};
watchdog@b017000 {
status = "okay";
};
};
keys {
compatible = "gpio-keys";
restart {
label = "reset";
linux,code = <KEY_RESTART>;
gpios = <&tlmm 63 GPIO_ACTIVE_LOW>;
debounce-interval = <60>;
};
};
leds {
compatible = "gpio-leds";
led_function_green: led-status-green {
function = LED_FUNCTION_STATUS;
color = <LED_COLOR_ID_GREEN>;
gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>;
};
led_function_red: led-status-red {
function = LED_FUNCTION_STATUS;
color = <LED_COLOR_ID_RED>;
gpios = <&tlmm 4 GPIO_ACTIVE_LOW>;
};
};
watchdog {
compatible = "linux,wdt-gpio";
gpios = <&tlmm 3 GPIO_ACTIVE_LOW>;
hw_algo = "toggle";
hw_margin_ms = <2>;
always-running;
};
virtual_flash {
compatible = "mtd-concat";
devices = <&fwconcat0 &fwconcat1>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "firmware";
reg = <0x0 0x3200000>;
compatible = "denx,fit";
};
};
};
};
&tlmm {
serial_pins: serial_pinmux {
mux {
pins = "gpio60", "gpio61";
function = "blsp_uart0";
bias-disable;
};
};
spi_0_pins: spi_0_pinmux {
pin {
function = "blsp_spi0";
pins = "gpio55", "gpio56", "gpio57";
drive-strength = <12>;
bias-disable;
};
pin_cs {
function = "gpio";
pins = "gpio54";
drive-strength = <2>;
bias-disable;
output-high;
};
};
};
&blsp_dma {
status = "okay";
};
&blsp1_spi1 {
pinctrl-0 = <&spi_0_pins>;
pinctrl-names = "default";
status = "okay";
cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>;
flash@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <24000000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition-flash-all@0 {
label = "flash-all";
reg = <0x00000000 0x4000000>;
read-only;
};
partition@0 {
label = "0:SBL1";
reg = <0x00 0x40000>;
read-only;
};
partition@40000 {
label = "0:MIBIB";
reg = <0x40000 0x40000>;
read-only;
};
partition@80000 {
label = "0:QSEE";
reg = <0x80000 0x80000>;
read-only;
};
partition@100000 {
label = "0:CDT";
reg = <0x100000 0x40000>;
read-only;
};
partition@140000 {
label = "0:DDRPARAMS";
reg = <0x140000 0x40000>;
read-only;
};
partition@180000 {
label = "0:APPSBL";
reg = <0x180000 0x100000>;
read-only;
};
partition@280000 {
label = "0:ART";
reg = <0x280000 0x40000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
precal_art_1000: precal@1000 {
reg = <0x1000 0x2f20>;
};
precal_art_5000: precal@5000 {
reg = <0x5000 0x2f20>;
};
precal_art_9000: precal@9000 {
reg = <0x9000 0x2f20>;
};
};
};
partition@2c0000 {
label = "0:APPSBLENV";
reg = <0x2c0000 0x40000>;
read-only;
};
partition@300000 {
label = "ResultA";
reg = <0x300000 0x80000>;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_resulta_10190: macaddr@10190 {
reg = <0x10190 0x6>;
};
};
};
partition@380000 {
label = "configA";
reg = <0x380000 0x280000>;
read-only;
};
partition@600000 {
label = "bootimageA";
reg = <0x600000 0x100000>;
read-only;
};
// In the vendor layout, the partition "SysImageA" lies here
// which encompassed the space of "uboot" and "fwconcat0"
partition@700000 {
label = "uboot";
reg = <0x700000 0x80000>;
};
fwconcat0: partition@780000 {
label = "fwconcat0";
reg = <0x780000 0x1880000>;
};
partition@2000000 {
label = "1:SBL1";
reg = <0x2000000 0x40000>;
read-only;
};
partition@2040000 {
label = "1:MIBIB";
reg = <0x2040000 0x40000>;
read-only;
};
partition@2080000 {
label = "1:QSEE";
reg = <0x2080000 0x80000>;
read-only;
};
partition@2100000 {
label = "1:CDT";
reg = <0x2100000 0x40000>;
read-only;
};
partition@2140000 {
label = "1:DDRPARAMS";
reg = <0x2140000 0x40000>;
read-only;
};
partition@2180000 {
label = "1:APPSBL";
reg = <0x2180000 0x100000>;
read-only;
};
partition@2280000 {
label = "Reservel";
reg = <0x2280000 0x80000>;
read-only;
};
partition@2300000 {
label = "ResultB";
reg = <0x2300000 0x80000>;
};
partition@2380000 {
label = "configB";
reg = <0x2380000 0x280000>;
read-only;
};
partition@2600000 {
label = "bootimageB";
reg = <0x2600000 0x100000>;
read-only;
};
// In the vendor layout, the partition "SysImageB" lies here
fwconcat1: partition@2700000 {
label = "fwconcat1";
reg = <0x2700000 0x1900000>;
};
};
};
};
&blsp1_uart1 {
pinctrl-0 = <&serial_pins>;
pinctrl-names = "default";
status = "okay";
};
&wifi0 {
status = "okay";
qcom,ath10k-calibration-variant = "huawei-ap4050dn";
};
&wifi1 {
status = "okay";
qcom,ath10k-calibration-variant = "huawei-ap4050dn";
};
&cryptobam {
status = "okay";
};
&mdio {
status = "okay";
};
&gmac {
status = "okay";
nvmem-cells = <&macaddr_resulta_10190 0>;
nvmem-cell-names = "mac-address";
};
&switch {
status = "okay";
};
&swport4 {
status = "okay";
label = "lan";
};
+12
View File
@@ -645,6 +645,18 @@ define Device/glinet_gl-s1300
endef
TARGET_DEVICES += glinet_gl-s1300
define Device/huawei_ap4050dn
$(call Device/FitImageLzma)
DEVICE_VENDOR := Huawei
DEVICE_MODEL := AP4050DN
SOC := qcom-ipq4018
IMAGE_SIZE := 51200k
DEVICE_PACKAGES := ipq-wifi-huawei_ap4050dn
KERNEL = kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | check-size | append-metadata
endef
TARGET_DEVICES += huawei_ap4050dn
define Device/kernel-size-6350-8300
DEVICE_COMPAT_VERSION := 2.0
DEVICE_COMPAT_MESSAGE := Kernel partition size must be increased for \
@@ -32,7 +32,7 @@ Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19032,6 +19032,13 @@ L: netdev@vger.kernel.org
@@ -19038,6 +19038,13 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/qualcomm/emac/
@@ -64,7 +64,7 @@ Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19038,6 +19038,7 @@ L: netdev@vger.kernel.org
@@ -19044,6 +19044,7 @@ L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/qcom,ipq4019-ess-edma.yaml
F: drivers/net/ethernet/qualcomm/ipqess/
@@ -57,7 +57,7 @@ Signed-off-by: Sky Huang <skylake.huang@mediatek.com>
+ };
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14434,9 +14434,10 @@ F: include/linux/pcs/pcs-mtk-usxgmii.h
@@ -14439,9 +14439,10 @@ F: include/linux/pcs/pcs-mtk-usxgmii.h
MEDIATEK ETHERNET PHY DRIVERS
M: Daniel Golle <daniel@makrotopia.org>
M: Qingfang Deng <dqfext@gmail.com>
@@ -20,7 +20,7 @@ Signed-off-by: Sky Huang <skylake.huang@mediatek.com>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14438,6 +14438,7 @@ M: Sky Huang <SkyLake.Huang@mediatek.com
@@ -14443,6 +14443,7 @@ M: Sky Huang <SkyLake.Huang@mediatek.com
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml
@@ -32,7 +32,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15154,6 +15154,13 @@ S: Maintained
@@ -15160,6 +15160,13 @@ S: Maintained
F: Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml
F: drivers/irqchip/irq-lan966x-oic.c
@@ -54,7 +54,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15159,7 +15159,7 @@ M: Daniel Machon <daniel.machon@microchi
@@ -15165,7 +15165,7 @@ M: Daniel Machon <daniel.machon@microchi
M: UNGLinuxDriver@microchip.com
L: netdev@vger.kernel.org
S: Maintained
@@ -226,7 +226,6 @@
};
enet0: ethernet@b0000 {
status = "okay";
phy-connection-type = "rgmii-id";
nvmem-cells = <&macaddr_hwinfo_0 0>;
nvmem-cell-names = "mac-address";
@@ -259,13 +258,27 @@
};
pci0: pcie@ffe09000 {
reg = <0 0xffe09000 0 0x1000>;
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
status = "disabled";
pcie@0 {
ranges = <0x2000000 0x0 0xa0000000
0x2000000 0x0 0xa0000000
0x0 0x20000000
0x1000000 0x0 0x0
0x1000000 0x0 0x0
0x0 0x100000>;
};
};
pci1: pcie@ffe0a000 {
reg = <0x0 0xffe0a000 0x0 0x1000>;
ranges = <0x2000000 0x0 0xc0000000 0x0 0xc0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0x0 0xffc20000 0x0 0x10000>;
0x1000000 0x0 0x00000000 0x0 0xffc20000 0x0 0x10000>;
reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
@@ -232,7 +232,22 @@
};
pci0: pcie@ffe09000 {
reg = <0 0xffe09000 0 0x1000>;
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
status = "disabled";
pcie@0 {
ranges = <0x2000000 0x0 0xa0000000
0x2000000 0x0 0xa0000000
0x0 0x20000000
0x1000000 0x0 0x0
0x1000000 0x0 0x0
0x0 0x100000>;
};
};
pci1: pcie@ffe0a000 {
@@ -49,7 +49,6 @@
d-cache-sets = <0x80>;
d-cache-size = <0x8000>;
d-cache-block-size = <0x20>;
status = "okay";
clock-frequency = <533333328>; /* 533.33 MHz */
bus-frequency = <266666664>; /* 266.66 MHz */
timebase-frequency = <33333333>; /* 33.33 MHz */
@@ -130,8 +129,6 @@
ranges = <0x0 0x0 0x0 0xec000000 0x4000000>;
nor@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0x0 0x0 0x4000000>;
bank-width = <2>;
@@ -334,7 +331,6 @@
rx-stash-idx = <0x00>;
rx-stash-len = <0x60>;
bd-stash;
status = "okay";
phy-handle = <&phy0>;
phy-connection-type = "rgmii-id";
nvmem-cells = <&macaddr_hwinfo_0 0>;
@@ -349,7 +345,6 @@
rx-stash-idx = <0x00>;
rx-stash-len = <0x60>;
bd-stash;
status = "okay";
phy-handle = <&phy1>;
phy-connection-type = "rgmii-id";
nvmem-cells = <&macaddr_hwinfo_0 1>;
@@ -194,13 +194,28 @@
};
pci0: pcie@ffe09000 {
reg = <0 0xffe09000 0 0x1000>;
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
status = "disabled";
pcie@0 {
ranges = <0x2000000 0x0 0xa0000000
0x2000000 0x0 0xa0000000
0x0 0x20000000
0x1000000 0x0 0x0
0x1000000 0x0 0x0
0x0 0x100000>;
};
};
pci1: pcie@ffe0a000 {
reg = <0 0xffe0a000 0 0x1000>;
ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
pcie@0 {
ranges = <0x2000000 0x0 0x80000000
0x2000000 0x0 0x80000000
@@ -391,6 +391,8 @@
};
ifc: ifc@ffe1e000 {
reg = <0x0 0xffe1e000 0 0x2000>;
status = "disabled";
};
@@ -67,8 +67,6 @@
ranges = <0x0 0x0 0x0 0xee000000 0x2000000>;
nor@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0x0 0x0 0x2000000>;
bank-width = <2>;
@@ -207,7 +205,6 @@
i-cache-size = <0x8000>;
i-cache-sets = <0x80>;
cpu-release-addr = <0x0 0x0ffff280>;
status = "okay";
enable-method = "spin-table";
};
@@ -140,6 +140,9 @@
};
ifc: ifc@ffe1e000 {
reg = <0x0 0xffe1e000 0 0x2000>;
status = "disabled";
};
pci0: pcie@ffe09000 {
@@ -94,8 +94,6 @@
ranges = <0x0 0x0 0x0 0xec000000 0x4000000>;
nor@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0x0 0x0 0x4000000>;
bank-width = <2>;
@@ -176,7 +174,6 @@
};
enet0: ethernet@b0000 {
status = "okay";
phy-handle = <&phy0>;
phy-connection-type = "rgmii-id";
};
@@ -186,7 +183,6 @@
};
enet2: ethernet@b2000 {
status = "okay";
phy-handle = <&phy2>;
phy-connection-type = "rgmii-id";
};
@@ -286,7 +282,6 @@
i-cache-size = <0x8000>;
i-cache-sets = <0x80>;
cpu-release-addr = <0x0 0x0ffff280>;
status = "okay";
enable-method = "spin-table";
};
@@ -16,7 +16,7 @@ Cc: Robert Marko <robert.marko@sartura.hr>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10972,6 +10972,22 @@ L: virtualization@lists.linux.dev
@@ -10978,6 +10978,22 @@ L: virtualization@lists.linux.dev
S: Supported
F: drivers/vdpa/ifcvf/
@@ -3,6 +3,7 @@
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <net/arp.h>
#include <net/lag.h>
#include <net/nexthop.h>
#include <net/neighbour.h>
#include <net/netevent.h>
@@ -287,7 +288,6 @@ static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
led_node = of_find_compatible_node(NULL, NULL, "realtek,rtl9300-leds");
for_each_node_by_name(dn, "port") {
phy_interface_t interface;
u32 led_set;
char led_set_str[16] = {0};
@@ -305,24 +305,15 @@ static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
}
if (pcs_node) {
priv->pcs[pn] = rtpcs_create(priv->dev, pcs_node, pn);
if (IS_ERR(priv->pcs[pn])) {
priv->ports[pn].pcs = rtpcs_create(priv->dev, pcs_node, pn);
if (IS_ERR(priv->ports[pn].pcs)) {
dev_err(priv->dev, "port %u failed to create PCS instance: %ld\n",
pn, PTR_ERR(priv->pcs[pn]));
priv->pcs[pn] = NULL;
pn, PTR_ERR(priv->ports[pn].pcs));
priv->ports[pn].pcs = NULL;
continue;
}
}
if (of_get_phy_mode(dn, &interface))
interface = PHY_INTERFACE_MODE_NA;
if (interface == PHY_INTERFACE_MODE_10G_QXGMII)
priv->ports[pn].is2G5 = true;
if (interface == PHY_INTERFACE_MODE_USXGMII)
priv->ports[pn].is2G5 = priv->ports[pn].is10G = true;
if (interface == PHY_INTERFACE_MODE_10GBASER)
priv->ports[pn].is10G = true;
priv->ports[pn].leds_on_this_port = 0;
if (led_node) {
if (of_property_read_u32(dn, "led-set", &led_set))
@@ -338,7 +329,7 @@ static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
}
if (!phy_node) {
if (priv->pcs[pn])
if (priv->ports[pn].pcs)
priv->ports[pn].phy_is_integrated = true;
continue;
@@ -394,9 +385,8 @@ static int rtl83xx_get_l2aging(struct rtl838x_switch_priv *priv)
int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_lag_upper_info *info)
{
struct rtl838x_switch_priv *priv = ds->priv;
int ret;
int i;
u32 algomsk = 0;
u32 algoidx = 0;
for (i = 0; i < priv->ds->num_lag_ids; i++) {
if (priv->lags_port_members[i] & BIT_ULL(port))
@@ -407,31 +397,16 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_la
return -ENOSPC;
}
switch (info->hash_type) {
case NETDEV_LAG_HASH_L2:
algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
break;
case NETDEV_LAG_HASH_L23:
algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
algoidx = 1;
break;
case NETDEV_LAG_HASH_L34:
algomsk |= TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT; /* sport */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT; /* dport */
algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
algoidx = 2;
break;
default:
algomsk |= 0x7f;
if (priv->r->lag_setup_algomask) {
ret = priv->r->lag_setup_algomask(priv, group, info);
if (ret)
return ret;
}
priv->r->set_distribution_algorithm(group, algoidx, algomsk);
priv->r->mask_port_reg_be(0, BIT_ULL(port), priv->r->trk_mbr_ctr(group));
priv->lags_port_members[group] |= BIT_ULL(port);
ret = priv->r->lag_set_port_members(priv, group,
priv->lags_port_members[group] | BIT_ULL(port), info);
if (ret)
return ret;
pr_info("%s: Added port %d to LAG %d. Members now %016llx.\n",
__func__, port, group, priv->lags_port_members[group]);
@@ -443,6 +418,7 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_la
int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
{
struct rtl838x_switch_priv *priv = ds->priv;
int ret;
if (group >= priv->ds->num_lag_ids) {
pr_err("%s: LAG %d invalid.\n", __func__, group);
@@ -454,9 +430,17 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
return -ENOSPC;
}
/* 0x7f algo mask all */
priv->r->mask_port_reg_be(BIT_ULL(port), 0, priv->r->trk_mbr_ctr(group));
priv->lags_port_members[group] &= ~BIT_ULL(port);
/* Don't touch hash mask bits, as only the port might be removed from
* the LAG group. This means the lag group stays valid with existing
* mask algo bits. If there are no lag members left, then
* rtl83xx_lag_add will reconfigure hash mask when new LAG group is
* created.
*/
ret = priv->r->lag_set_port_members(priv, group,
priv->lags_port_members[group] & ~BIT_ULL(port),
NULL);
if (ret)
return ret;
pr_info("%s: Removed port %d from LAG %d. Members now %016llx.\n",
__func__, port, group, priv->lags_port_members[group]);
@@ -464,6 +448,234 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
return 0;
}
int rtldsa_93xx_lag_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
int group, int algoidx, u32 algomsk)
{
bool is_l3 = false;
u32 newmask = 0;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SIP_BIT) {
is_l3 = true;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SIP_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DIP_BIT) {
is_l3 = true;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DIP_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) {
is_l3 = true;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT) {
is_l3 = true;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DST_L4PORT_BIT;
}
if (is_l3) {
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SPA_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SPA_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SMAC_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DMAC_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_VLAN_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_VLAN_BIT;
} else {
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SPA_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L2_SPA_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L2_DMAC_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_VLAN_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L2_VLAN_BIT;
}
sw_w32(newmask, priv->r->trk_hash_ctrl + (algoidx << 2));
return 0;
}
int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
struct netdev_lag_upper_info *info)
{
u32 algomsk = 0;
u32 algoidx = 0;
switch (info->hash_type) {
case NETDEV_LAG_HASH_L2:
algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
break;
case NETDEV_LAG_HASH_L23:
algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
algoidx = 1;
break;
case NETDEV_LAG_HASH_L34:
algomsk |= TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT; /* sport */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT; /* dport */
algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
algoidx = 2;
break;
default:
algomsk |= TRUNK_DISTRIBUTION_ALGO_MASKALL;
}
return priv->r->lag_set_distribution_algorithm(priv, group, algoidx, algomsk);
}
static int rtldsa_93xx_lag_set_group2ports(struct rtl838x_switch_priv *priv, int group,
struct netdev_lag_upper_info *info)
{
DECLARE_BITMAP(ports, ARRAY_SIZE(priv->ports));
struct rtldsa_93xx_lag_entry e;
unsigned int table_pos = 0;
u8 num_of_lag_ports = 0;
u8 group_ports[8];
u32 data[3];
int i;
/* Read lag table using Table control register 2 */
struct table_reg *r = priv->r->lag_table();
rtl_table_read(r, group);
bitmap_clear(ports, 0, ARRAY_SIZE(priv->ports));
bitmap_from_arr64(ports, &priv->lags_port_members[group],
ARRAY_SIZE(priv->ports));
for (i = 0; i < 3; i++)
data[i] = sw_r32(rtl_table_data(r, i));
priv->r->lag_fill_data(data, &e);
num_of_lag_ports = bitmap_weight(ports, ARRAY_SIZE(priv->ports));
if (num_of_lag_ports > ARRAY_SIZE(group_ports)) {
pr_err("%s: Number of LAG ports too high: %u", __func__,
num_of_lag_ports);
return -ENOSPC;
}
memset(group_ports, 0x3f, sizeof(group_ports));
table_pos = 0;
for_each_set_bit(i, ports, ARRAY_SIZE(priv->ports)) {
struct net_device *lag_slave = priv->ports[i].dp->user;
if (lag_slave && !net_lag_port_dev_txable(lag_slave))
continue;
group_ports[table_pos] = i;
table_pos++;
}
/* Remove tx disabled ports */
num_of_lag_ports = table_pos;
e.trk_dev0 = 0;
e.trk_port0 = group_ports[0];
e.trk_dev1 = 0;
e.trk_port1 = group_ports[1];
e.trk_dev2 = 0;
e.trk_port2 = group_ports[2];
e.trk_dev3 = 0;
e.trk_port3 = group_ports[3];
e.trk_dev4 = 0;
e.trk_port4 = group_ports[4];
e.trk_dev5 = 0;
e.trk_port5 = group_ports[5];
e.trk_dev6 = 0;
e.trk_port6 = group_ports[6];
e.trk_dev7 = 0;
e.trk_port7 = group_ports[7];
e.num_tx_candi = num_of_lag_ports;
/* set hash_mask_idx to 0 if we are deleting lag group */
if (info) {
if (info->hash_type == NETDEV_LAG_HASH_L2) {
e.l2_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L2;
e.ip4_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L2;
e.ip6_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L2;
} else if (info->hash_type == NETDEV_LAG_HASH_L23) {
e.l2_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L23;
e.ip4_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L23;
e.ip6_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L23;
} else {
return -EOPNOTSUPP;
}
}
priv->r->lag_write_data(data, &e);
for (i = 0; i < 3; i++)
sw_w32(data[i], rtl_table_data(r, i));
rtl_table_write(r, group);
rtl_table_release(r);
return 0;
}
static inline void rtldsa_93xx_lag_set_local_group2ports(struct rtl838x_switch_priv *priv, int group,
u64 ports)
{
priv->r->set_port_reg_be(ports, priv->r->trk_mbr_ctr(group));
}
int rtldsa_93xx_lag_set_port_members(struct rtl838x_switch_priv *priv, int group,
u64 members, struct netdev_lag_upper_info *info)
{
DECLARE_BITMAP(affected_members, ARRAY_SIZE(priv->ports));
bool valid_group;
u64 old_members;
u64 affected;
size_t port;
int ret;
/* calculate modifications of the LAG group */
old_members = priv->lags_port_members[group];
priv->lags_port_members[group] = members;
affected = old_members | priv->lags_port_members[group];
bitmap_clear(affected_members, 0, ARRAY_SIZE(priv->ports));
bitmap_from_arr64(affected_members, &affected, BITS_PER_TYPE(affected));
valid_group = __sw_hweight64(priv->lags_port_members[group]);
/* apply global group and port settings */
ret = rtldsa_93xx_lag_set_group2ports(priv, group, info);
if (ret)
return ret;
for_each_set_bit(port, affected_members, ARRAY_SIZE(priv->ports)) {
bool valid = priv->lags_port_members[group] & BIT_ULL(port);
priv->r->lag_set_port2group(group, port, valid);
}
/* apply local group and port settings */
priv->r->lag_set_local_group_id(group, group, valid_group);
rtldsa_93xx_lag_set_local_group2ports(priv, group, priv->lags_port_members[group]);
for_each_set_bit(port, affected_members, ARRAY_SIZE(priv->ports)) {
bool valid = priv->lags_port_members[group] & BIT_ULL(port);
priv->r->lag_set_local_port2group(group, port, valid);
}
/* write lag table (and maybe additional information) to SRAM */
priv->r->lag_sync_tables();
return 0;
}
// Currently Unused
// /* Allocate a 64 bit octet counter located in the LOG HW table */
// static int rtl83xx_octet_cntr_alloc(struct rtl838x_switch_priv *priv)
@@ -1574,6 +1786,9 @@ static int rtl83xx_sw_probe(struct platform_device *pdev)
break;
}
if (priv->r->lag_switch_init)
priv->r->lag_switch_init(priv);
return 0;
err_register_fib_nb:
@@ -1586,6 +1801,30 @@ err_register_switch:
return err;
}
void rtldsa_93xx_lag_switch_init(struct rtl838x_switch_priv *priv)
{
u32 trk_ctrlmask = 0;
u32 algomask;
trk_ctrlmask |= RTL93XX_TRK_CTRL_NON_TMN_TUNNEL_HASH_SEL;
trk_ctrlmask |= RTL93XX_TRK_CTRL_TRK_STAND_ALONE_MODE;
trk_ctrlmask |= RTL93XX_TRK_CTRL_LOCAL_FIRST;
sw_w32(trk_ctrlmask, priv->r->trk_ctrl);
/* Setup NETDEV_LAG_HASH_L2 on slot 0 */
algomask = TRUNK_DISTRIBUTION_ALGO_SMAC_BIT |
TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
priv->r->lag_set_distribution_algorithm(priv, 0, RTL93XX_HASH_MASK_INDEX_L2, algomask);
/* Setup NETDEV_LAG_HASH_L23 on slot 1 */
algomask = TRUNK_DISTRIBUTION_ALGO_SMAC_BIT |
TRUNK_DISTRIBUTION_ALGO_DMAC_BIT |
TRUNK_DISTRIBUTION_ALGO_SIP_BIT |
TRUNK_DISTRIBUTION_ALGO_DIP_BIT;
priv->r->lag_set_distribution_algorithm(priv, 0, RTL93XX_HASH_MASK_INDEX_L23, algomask);
}
static void rtl83xx_sw_remove(struct platform_device *pdev)
{
struct rtl838x_switch_priv *priv = platform_get_drvdata(pdev);
@@ -160,7 +160,7 @@ static ssize_t rtl838x_common_write(const char __user *buffer, size_t count,
static ssize_t stp_state_read(struct file *filp, char __user *buffer, size_t count,
loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct rtldsa_port *p = filp->private_data;
struct dsa_switch *ds = p->dp->ds;
int state = rtldsa_port_get_stp_state(ds->priv, p->dp->index);
@@ -173,7 +173,7 @@ static ssize_t stp_state_read(struct file *filp, char __user *buffer, size_t cou
static ssize_t stp_state_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct rtldsa_port *p = filp->private_data;
u32 value;
size_t res = rtl838x_common_write(buffer, count, ppos, &value);
@@ -268,6 +268,13 @@ static void l2_table_print_entry(struct seq_file *m, struct rtl838x_switch_priv
e->vid, e->rvid);
seq_printf(m, " port %d age %d", e->port, e->age);
if (e->is_trunk) {
seq_printf(m, " trunk %d trunk_members: 0x%08llx non-primary: 0x%08llx primary-port: %d",
e->trunk,
priv->lags_port_members[e->trunk],
priv->lag_non_primary,
priv->lag_primary[e->trunk]);
}
if (e->is_static)
seq_puts(m, " static");
if (e->block_da)
@@ -586,7 +593,7 @@ static const struct file_operations rtldsa_vlan_table_fops = {
static ssize_t age_out_read(struct file *filp, char __user *buffer, size_t count,
loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct rtldsa_port *p = filp->private_data;
struct dsa_switch *ds = p->dp->ds;
struct rtl838x_switch_priv *priv = ds->priv;
int value = sw_r32(priv->r->l2_port_aging_out);
@@ -600,7 +607,7 @@ static ssize_t age_out_read(struct file *filp, char __user *buffer, size_t count
static ssize_t age_out_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct rtldsa_port *p = filp->private_data;
u32 value;
size_t res = rtl838x_common_write(buffer, count, ppos, &value);
@@ -622,7 +629,7 @@ static const struct file_operations age_out_fops = {
static ssize_t port_egress_rate_read(struct file *filp, char __user *buffer, size_t count,
loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct rtldsa_port *p = filp->private_data;
struct dsa_switch *ds = p->dp->ds;
struct rtl838x_switch_priv *priv = ds->priv;
int value;
@@ -641,7 +648,7 @@ static ssize_t port_egress_rate_read(struct file *filp, char __user *buffer, siz
static ssize_t port_egress_rate_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct rtldsa_port *p = filp->private_data;
struct dsa_switch *ds = p->dp->ds;
struct rtl838x_switch_priv *priv = ds->priv;
u32 value;
@@ -50,7 +50,7 @@ static void rtldsa_enable_phy_polling(struct rtl838x_switch_priv *priv)
msleep(1000);
/* Enable all ports with a PHY, including the SFP-ports */
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy || priv->pcs[i])
if (priv->ports[i].phy || priv->ports[i].pcs)
v |= BIT_ULL(i);
}
@@ -180,7 +180,7 @@ static int rtldsa_83xx_setup(struct dsa_switch *ds)
* they will work in isolated mode (only traffic between port and CPU).
*/
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy || priv->pcs[i]) {
if (priv->ports[i].phy || priv->ports[i].pcs) {
priv->ports[i].pm = BIT_ULL(priv->cpu_port);
priv->r->traffic_set(i, BIT_ULL(i));
}
@@ -253,7 +253,7 @@ static int rtldsa_93xx_setup(struct dsa_switch *ds)
* they will work in isolated mode (only traffic between port and CPU).
*/
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy || priv->pcs[i]) {
if (priv->ports[i].phy || priv->ports[i].pcs) {
priv->ports[i].pm = BIT_ULL(priv->cpu_port);
priv->r->traffic_set(i, BIT_ULL(i));
}
@@ -291,7 +291,7 @@ static struct phylink_pcs *rtldsa_phylink_mac_select_pcs(struct dsa_switch *ds,
{
struct rtl838x_switch_priv *priv = ds->priv;
return priv->pcs[port];
return priv->ports[port].pcs;
}
static void rtldsa_83xx_phylink_get_caps(struct dsa_switch *ds, int port,
@@ -767,7 +767,7 @@ static void rtldsa_poll_counters(struct work_struct *work)
counters_work);
for (int port = 0; port < priv->cpu_port; port++) {
if (!priv->ports[port].phy && !priv->pcs[port])
if (!priv->ports[port].phy && !priv->ports[port].pcs)
continue;
rtldsa_counters_lock(priv, port);
@@ -784,7 +784,7 @@ static void rtldsa_init_counters(struct rtl838x_switch_priv *priv)
struct rtldsa_counter_state *counters;
for (int port = 0; port < priv->cpu_port; port++) {
if (!priv->ports[port].phy && !priv->pcs[port])
if (!priv->ports[port].phy && !priv->ports[port].pcs)
continue;
counters = &priv->ports[port].counters;
@@ -1360,10 +1360,10 @@ static void rtldsa_update_port_member(struct rtl838x_switch_priv *priv, int port
__must_hold(&priv->reg_mutex)
{
struct dsa_port *dp = dsa_to_port(priv->ds, port);
struct rtl838x_port *p = &priv->ports[port];
struct rtldsa_port *p = &priv->ports[port];
struct dsa_port *cpu_dp = dp->cpu_dp;
u64 port_mask = BIT_ULL(cpu_dp->index);
struct rtl838x_port *other_p;
struct rtldsa_port *other_p;
struct dsa_port *other_dp;
int other_port;
bool isolated;
@@ -1865,6 +1865,39 @@ static int rtldsa_find_l2_cam_entry(struct rtl838x_switch_priv *priv, u64 seed,
return idx;
}
/**
* rtldsa_find_lag_group_from_port() - Find lag group of current port
* @priv: private data of rtldsa switch
* @port: port id of potential LAG member
* Return: -ENOENT when port does not belong to any lag group, lag id otherwise
*/
static int rtldsa_find_lag_group_from_port(struct rtl838x_switch_priv *priv, int port)
{
if (!(priv->lagmembers & BIT_ULL(port)))
return -ENOENT;
/* port is a lag member */
for (int lag_group = 0; lag_group < MAX_LAGS; lag_group++) {
if (priv->lags_port_members[lag_group] & BIT_ULL(port))
return lag_group;
}
return -ENOENT;
}
/**
* rtldsa_93xx_prepare_lag_fdb() - Prepare fdb entry for LAG
* @e: L2 entry data
* @lag_group: lag id of the trunk group
*/
inline void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group)
{
if (e && lag_group >= 0) {
e->is_trunk = true;
e->trunk = lag_group;
}
}
static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
const struct dsa_db db)
@@ -1874,10 +1907,16 @@ static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port,
struct rtl838x_l2_entry e;
int err = 0, idx;
u64 seed = priv->r->l2_hash_seed(mac, vid);
int lag_group = rtldsa_find_lag_group_from_port(priv, port);
if (priv->lag_non_primary & BIT_ULL(port)) {
pr_debug("%s: %d is lag slave. ignore\n", __func__, port);
return 0;
if (lag_group >= 0 && priv->r->prepare_lag_fdb) {
priv->r->prepare_lag_fdb(&e, lag_group);
} else {
if (priv->lag_non_primary & BIT_ULL(port)) {
pr_debug("%s: %d is lag slave but prepare_lag_fdb is not supported. ignore\n",
__func__, port);
return 0;
}
}
mutex_lock(&priv->reg_mutex);
@@ -1917,8 +1956,13 @@ static int rtldsa_port_fdb_del(struct dsa_switch *ds, int port,
struct rtl838x_l2_entry e;
int err = 0, idx;
u64 seed = priv->r->l2_hash_seed(mac, vid);
int lag_group = rtldsa_find_lag_group_from_port(priv, port);
if (lag_group >= 0 && priv->r->prepare_lag_fdb)
priv->r->prepare_lag_fdb(&e, lag_group);
pr_debug("In %s, mac %llx, vid: %d\n", __func__, mac, vid);
mutex_lock(&priv->reg_mutex);
idx = rtldsa_find_l2_hash_entry(priv, seed, true, &e);
@@ -1960,6 +2004,10 @@ static int rtldsa_port_fdb_dump(struct dsa_switch *ds, int port,
if (!e.valid)
continue;
// Ignore trunk fdb entries
if (e.is_trunk)
continue;
if (e.port == port || e.port == RTL930X_PORT_IGNORE)
cb(e.mac, e.vid, e.is_static, data);
@@ -1973,6 +2021,10 @@ static int rtldsa_port_fdb_dump(struct dsa_switch *ds, int port,
if (!e.valid)
continue;
// Ignore trunk fdb entries
if (e.is_trunk)
continue;
if (e.port == port)
cb(e.mac, e.vid, e.is_static, data);
}
@@ -2325,8 +2377,28 @@ static bool rtldsa_83xx_lag_can_offload(struct dsa_switch *ds,
static int rtldsa_port_lag_change(struct dsa_switch *ds, int port)
{
pr_debug("%s: %d\n", __func__, port);
/* Nothing to be done... */
struct dsa_port *dp = dsa_to_port(ds, port);
struct rtl838x_switch_priv *priv = ds->priv;
int lag_group;
int ret;
if (!dp)
return -EINVAL;
lag_group = rtldsa_find_lag_group_from_port(priv, port);
if (lag_group < 0)
return lag_group;
if (priv->r->lag_set_port_members) {
/* Set same port members again, the function should check against
* lag_tx_enabled and set egress ports accordingly.
*/
ret = priv->r->lag_set_port_members(priv, lag_group,
priv->lags_port_members[lag_group],
NULL);
if (ret)
return ret;
}
return 0;
}
@@ -2396,7 +2468,6 @@ static int rtldsa_port_lag_leave(struct dsa_switch *ds, int port,
}
pr_info("port_lag_del: group %d, port %d\n", group, port);
priv->lagmembers &= ~BIT_ULL(port);
priv->lag_primary[group] = -1;
priv->lag_non_primary &= ~BIT_ULL(port);
pr_debug("lag_members = %llX\n", priv->lagmembers);
err = rtl83xx_lag_del(priv->ds, group, port);
@@ -2405,6 +2476,19 @@ static int rtldsa_port_lag_leave(struct dsa_switch *ds, int port,
goto out;
}
/* To re-elect primary interface, just remove the first interface in
* this-group's interfaces from non-primary
*/
if (priv->lags_port_members[group]) {
priv->lag_primary[group] = fls64(priv->lags_port_members[group]);
priv->lag_non_primary &= ~BIT_ULL(priv->lag_primary[group]);
}
/* No need to update fdb entries since they make use of trunk_id for entry.
* The primary interface is only calculated at time of
* port_fdb_dump
*/
out:
mutex_unlock(&priv->reg_mutex);
return 0;
@@ -2467,7 +2551,7 @@ static int rtldsa_cls_flower_add(struct dsa_switch *ds, int port,
bool ingress)
{
struct rtl838x_switch_priv *priv = ds->priv;
struct rtl838x_port *p = &priv->ports[port];
struct rtldsa_port *p = &priv->ports[port];
const struct flow_action_entry *act;
int ret;
@@ -2513,7 +2597,7 @@ static int rtldsa_cls_flower_del(struct dsa_switch *ds, int port,
bool ingress)
{
struct rtl838x_switch_priv *priv = ds->priv;
struct rtl838x_port *p = &priv->ports[port];
struct rtldsa_port *p = &priv->ports[port];
int ret;
if (!priv->r->port_rate_police_del)
@@ -1748,12 +1748,14 @@ static void rtl838x_set_egr_filter(int port, enum egr_filter state)
RTL838X_VLAN_PORT_EGR_FLTR + (((port / 29) << 2)));
}
static void rtl838x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
static int rtldsa_838x_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
int group, int algoidx, u32 algomsk)
{
algoidx &= 1; /* RTL838X only supports 2 concurrent algorithms */
sw_w32_mask(1 << (group % 8), algoidx << (group % 8),
RTL838X_TRK_HASH_IDX_CTRL + ((group >> 3) << 2));
sw_w32(algomsk, RTL838X_TRK_HASH_CTRL + (algoidx << 2));
return 0;
}
static void rtl838x_set_receive_management_action(int port, rma_ctrl_t type, action_type_t action)
@@ -1790,6 +1792,20 @@ rtldsa_838x_vlan_profile_dump(struct rtl838x_switch_priv *priv, int idx)
p.unkn_mc_fld.pmsks_idx.ip, p.unkn_mc_fld.pmsks_idx.ip6);
}
static int rtldsa_838x_lag_set_port_members(struct rtl838x_switch_priv *priv, int group,
u64 members, struct netdev_lag_upper_info *info)
{
priv->lags_port_members[group] = members;
priv->r->set_port_reg_be(priv->lags_port_members[group],
priv->r->trk_mbr_ctr(group));
return 0;
}
int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
struct netdev_lag_upper_info *info);
const struct rtldsa_config rtldsa_838x_cfg = {
.mask_port_reg_be = rtl838x_mask_port_reg,
.set_port_reg_be = rtl838x_set_port_reg,
@@ -1875,9 +1891,11 @@ const struct rtldsa_config rtldsa_838x_cfg = {
.route_read = rtl838x_route_read,
.route_write = rtl838x_route_write,
.l3_setup = rtl838x_l3_setup,
.set_distribution_algorithm = rtl838x_set_distribution_algorithm,
.set_receive_management_action = rtl838x_set_receive_management_action,
.qos_init = rtldsa_838x_qos_init,
.lag_set_distribution_algorithm = rtldsa_838x_set_distribution_algorithm,
.lag_set_port_members = rtldsa_838x_lag_set_port_members,
.lag_setup_algomask = rtldsa_83xx_lag_setup_algomask,
};
irqreturn_t rtl838x_switch_irq(int irq, void *dev_id)
@@ -371,32 +371,32 @@
#define RTL839X_IGR_BWCTRL_CTRL_LB_THR (0x1614)
/* Link aggregation (Trunking) */
#define TRUNK_DISTRIBUTION_ALGO_SPA_BIT 0x01
#define TRUNK_DISTRIBUTION_ALGO_SMAC_BIT 0x02
#define TRUNK_DISTRIBUTION_ALGO_DMAC_BIT 0x04
#define TRUNK_DISTRIBUTION_ALGO_SIP_BIT 0x08
#define TRUNK_DISTRIBUTION_ALGO_DIP_BIT 0x10
#define TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT 0x20
#define TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT 0x40
#define TRUNK_DISTRIBUTION_ALGO_MASKALL 0x7F
#define TRUNK_DISTRIBUTION_ALGO_SPA_BIT BIT(0)
#define TRUNK_DISTRIBUTION_ALGO_SMAC_BIT BIT(1)
#define TRUNK_DISTRIBUTION_ALGO_DMAC_BIT BIT(2)
#define TRUNK_DISTRIBUTION_ALGO_L2_SPA_BIT 0x01
#define TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT 0x02
#define TRUNK_DISTRIBUTION_ALGO_L2_DMAC_BIT 0x04
#define TRUNK_DISTRIBUTION_ALGO_L2_VLAN_BIT 0x08
#define TRUNK_DISTRIBUTION_ALGO_L2_MASKALL 0xF
#define TRUNK_DISTRIBUTION_ALGO_SIP_BIT BIT(3)
#define TRUNK_DISTRIBUTION_ALGO_DIP_BIT BIT(4)
#define TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT BIT(5)
#define TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT BIT(6)
#define TRUNK_DISTRIBUTION_ALGO_VLAN_BIT BIT(7)
#define TRUNK_DISTRIBUTION_ALGO_MASKALL GENMASK(6, 0)
#define TRUNK_DISTRIBUTION_ALGO_L3_SPA_BIT 0x01
#define TRUNK_DISTRIBUTION_ALGO_L3_SMAC_BIT 0x02
#define TRUNK_DISTRIBUTION_ALGO_L3_DMAC_BIT 0x04
#define TRUNK_DISTRIBUTION_ALGO_L3_VLAN_BIT 0x08
#define TRUNK_DISTRIBUTION_ALGO_L3_SIP_BIT 0x10
#define TRUNK_DISTRIBUTION_ALGO_L3_DIP_BIT 0x20
#define TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT 0x40
#define TRUNK_DISTRIBUTION_ALGO_L3_DST_L4PORT_BIT 0x80
#define TRUNK_DISTRIBUTION_ALGO_L3_PROTO_BIT 0x100
#define TRUNK_DISTRIBUTION_ALGO_L3_FLOW_LABEL_BIT 0x200
#define TRUNK_DISTRIBUTION_ALGO_L3_MASKALL 0x3FF
#define TRUNK_DISTRIBUTION_ALGO_L2_SPA_BIT BIT(0)
#define TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT BIT(1)
#define TRUNK_DISTRIBUTION_ALGO_L2_DMAC_BIT BIT(2)
#define TRUNK_DISTRIBUTION_ALGO_L2_VLAN_BIT BIT(3)
#define TRUNK_DISTRIBUTION_ALGO_L3_SPA_BIT BIT(4 + 0)
#define TRUNK_DISTRIBUTION_ALGO_L3_SMAC_BIT BIT(4 + 1)
#define TRUNK_DISTRIBUTION_ALGO_L3_DMAC_BIT BIT(4 + 2)
#define TRUNK_DISTRIBUTION_ALGO_L3_VLAN_BIT BIT(4 + 3)
#define TRUNK_DISTRIBUTION_ALGO_L3_SIP_BIT BIT(4 + 4)
#define TRUNK_DISTRIBUTION_ALGO_L3_DIP_BIT BIT(4 + 5)
#define TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT BIT(4 + 6)
#define TRUNK_DISTRIBUTION_ALGO_L3_DST_L4PORT_BIT BIT(4 + 7)
#define TRUNK_DISTRIBUTION_ALGO_L3_PROTO_BIT BIT(4 + 8)
#define TRUNK_DISTRIBUTION_ALGO_L3_FLOW_LABEL_BIT BIT(4 + 9)
#define RTL838X_TRK_MBR_CTR (0x3E00)
#define RTL838X_TRK_HASH_IDX_CTRL (0x3E20)
@@ -406,11 +406,98 @@
#define RTL839X_TRK_HASH_IDX_CTRL (0x2280)
#define RTL839X_TRK_HASH_CTRL (0x2284)
#define RTL930X_LOCAL_PORT_TRK_MAP (0xD0C8)
#define RTL930X_TRK_ID_CTRL (0xA3A8)
#define RTL930X_TRK_MBR_CTRL (0xA41C)
#define RTL930X_TRK_HASH_CTRL (0x9F80)
#define RTL930X_TRK_CTRL (0x9F88)
#define RTL930X_TRK_SHIFT_CTRL (0x9F8C)
#define RTL930X_TRK_LOCAL_TBL_REFRESH (0x9F90)
#define RTL930X_TRK_LOCAL_TBL (0x9F94)
#define RTL930X_TRK_STK_CTRL (0xA07C)
#define RTL930X_TRK_ID_CTRL_TRK_VALID BIT(6)
#define RTL930X_TRK_ID_CTRL_TRK_ID GENMASK(5, 0)
#define RTL930X_LOCAL_PORT_TRK_MAP_IS_TRK_MBR BIT(6)
#define RTL930X_LOCAL_PORT_TRK_MAP_TRK_ID GENMASK(5, 0)
#define RTL930X_SRC_TRK_MAP_TRK_VALID BIT(31)
#define RTL930X_SRC_TRK_MAP_TRK_ID GENMASK(30, 25)
#define RTL931X_LOCAL_PORT_TRK_MAP (0x4CAC)
#define RTL931X_TRK_ID_CTRL (0xB800)
#define RTL931X_TRK_MBR_CTRL (0xB8D0)
#define RTL931X_TRK_HASH_CTRL (0xBA70)
#define RTL931X_TRK_CTRL (0xBA78)
#define RTL931X_TRK_SHIFT_CTRL (0xBA7C)
#define RTL931X_TRK_LOCAL_TBL_REFRESH (0xBA80)
#define RTL931X_TRK_LOCAL_TBL (0xBA84)
#define RTL931X_TRK_STK_CTRL (0xBE94)
#define RLT931X_TRK_ID_CTRL_TRK_ID GENMASK(6, 0)
#define RTL931X_TRK_ID_CTRL_TRK_VALID BIT(7)
#define RTL931X_LOCAL_PORT_TRK_MAP_IS_TRK_MBR BIT(7)
#define RTL931X_LOCAL_PORT_TRK_MAP_TRK_ID GENMASK(6, 0)
#define RTL931X_SRC_TRK_MAP_TRK_ID GENMASK(30, 24)
#define RTL931X_SRC_TRK_MAP_TRK_ID_VALID BIT(31)
#define GENMASK_MOD(high, low) GENMASK((high) % 32, (low) % 32)
#define BIT_MOD(bit) BIT((bit) % 32)
/* RTL930X LAG Table offsets */
#define RTL930X_LAG_NUM_TX_CANDI GENMASK_MOD(92, 89)
#define RTL930X_LAG_L2_HASH_MSK_IDX BIT_MOD(88)
#define RTL930X_LAG_IP4_HASH_MSK_IDX BIT_MOD(87)
#define RTL930X_LAG_IP6_HASH_MSK_IDX BIT_MOD(86)
#define RTL930X_LAG_SEP_DLF_BCAST_EN BIT_MOD(85)
#define RTL930X_LAG_SEP_KWN_MC_EN BIT_MOD(84)
#define RTL930X_LAG_TRK_DEV7 GENMASK_MOD(83, 80)
#define RTL930X_LAG_TRK_PORT7 GENMASK_MOD(79, 74)
#define RTL930X_LAG_TRK_DEV6 GENMASK_MOD(73, 70)
#define RTL930X_LAG_TRK_PORT6 GENMASK_MOD(69, 64)
#define RTL930X_LAG_TRK_DEV5 GENMASK_MOD(61, 58)
#define RTL930X_LAG_TRK_PORT5 GENMASK_MOD(57, 52)
#define RTL930X_LAG_TRK_DEV4 GENMASK_MOD(51, 48)
#define RTL930X_LAG_TRK_PORT4 GENMASK_MOD(47, 42)
#define RTL930X_LAG_TRK_DEV3 GENMASK_MOD(41, 38)
#define RTL930X_LAG_TRK_PORT3 GENMASK_MOD(37, 32)
#define RTL930X_LAG_TRK_DEV2 GENMASK_MOD(29, 26)
#define RTL930X_LAG_TRK_PORT2 GENMASK_MOD(25, 20)
#define RTL930X_LAG_TRK_DEV1 GENMASK_MOD(19, 16)
#define RTL930X_LAG_TRK_PORT1 GENMASK_MOD(15, 10)
#define RTL930X_LAG_TRK_DEV0 GENMASK_MOD(9, 6)
#define RTL930X_LAG_TRK_PORT0 GENMASK_MOD(5, 0)
/* RTL931X LAG Table offsets */
#define RTL931X_LAG_NUM_TX_CANDI GENMASK_MOD(92, 89)
#define RTL931X_LAG_L2_HASH_MSK_IDX BIT_MOD(88)
#define RTL931X_LAG_IP4_HASH_MSK_IDX BIT_MOD(87)
#define RTL931X_LAG_IP6_HASH_MSK_IDX BIT_MOD(86)
#define RTL931X_LAG_SEP_FLOOD_EN BIT_MOD(85)
#define RTL931X_LAG_SEP_KWN_MC_EN BIT_MOD(84)
#define RTL931X_LAG_TRK_DEV7 GENMASK_MOD(83, 80)
#define RTL931X_LAG_TRK_PORT7 GENMASK_MOD(79, 74)
#define RTL931X_LAG_TRK_DEV6 GENMASK_MOD(73, 70)
#define RTL931X_LAG_TRK_PORT6 GENMASK_MOD(69, 64)
#define RTL931X_LAG_TRK_DEV5 GENMASK_MOD(61, 58)
#define RTL931X_LAG_TRK_PORT5 GENMASK_MOD(57, 52)
#define RTL931X_LAG_TRK_DEV4 GENMASK_MOD(51, 48)
#define RTL931X_LAG_TRK_PORT4 GENMASK_MOD(47, 42)
#define RTL931X_LAG_TRK_DEV3 GENMASK_MOD(41, 38)
#define RTL931X_LAG_TRK_PORT3 GENMASK_MOD(37, 32)
#define RTL931X_LAG_TRK_DEV2 GENMASK_MOD(29, 26)
#define RTL931X_LAG_TRK_PORT2 GENMASK_MOD(25, 20)
#define RTL931X_LAG_TRK_DEV1 GENMASK_MOD(19, 16)
#define RTL931X_LAG_TRK_PORT1 GENMASK_MOD(15, 10)
#define RTL931X_LAG_TRK_DEV0 GENMASK_MOD(9, 6)
#define RTL931X_LAG_TRK_PORT0 GENMASK_MOD(5, 0)
/* Attack prevention */
#define RTL838X_ATK_PRVNT_PORT_EN (0x5B00)
@@ -511,6 +598,16 @@
#define RTL838X_LED_SW_P_CTRL (0xA01C)
#define RTL838X_LED_SW_P_CTRL_PORT(p) (RTL838X_LED_SW_P_CTRL + (((p) << 2)))
#define RTL93XX_HASH_MASK_INDEX_L2 (0)
#define RTL93XX_HASH_MASK_INDEX_L23 (1)
#define RTL93XX_TRK_CTRL_NON_TMN_TUNNEL_HASH_SEL BIT(0)
#define RTL93XX_TRK_CTRL_SEP_PORT_SEL BIT(1)
#define RTL93XX_TRK_CTRL_TRK_STAND_ALONE_MODE BIT(2)
#define RTL93XX_TRK_CTRL_STK_HASH_CAL BIT(3)
#define RTL93XX_TRK_CTRL_LOCAL_FIRST BIT(4)
#define RTL93XX_TRK_CTRL_CONGST_AVOID BIT(5)
#define RTL93XX_TRK_CTRL_LINK_DOWN_AVOID BIT(6)
/* special port action controls */
/* values:
@@ -874,11 +971,39 @@ struct rtldsa_counter_state {
struct rtnl_link_stats64 link_stat;
};
struct rtl838x_port {
struct rtldsa_93xx_lag_entry {
u32 trk_port0:6;
u32 trk_dev0:4;
u32 trk_port1:6;
u32 trk_dev1:4;
u32 trk_port2:6;
u32 trk_dev2:4;
u32 trk_port3:6;
u32 trk_dev3:4;
u32 trk_port4:6;
u32 trk_dev4:4;
u32 trk_port5:6;
u32 trk_dev5:4;
u32 trk_port6:6;
u32 trk_dev6:4;
u32 trk_port7:6;
u32 trk_dev7:4;
u32 sep_kwn_mc_en:1;
union {
// for rtl930x
u32 sep_dlf_bcast_en:1;
// for rtl931x
u32 sep_flood_en:1;
} flood_dlf_bcast;
u32 ip6_hash_mask_idx:1;
u32 ip4_hash_mask_idx:1;
u32 l2_hash_mask_idx:1;
u32 num_tx_candi:4;
};
struct rtldsa_port {
bool enable:1;
bool phy_is_integrated:1;
bool is10G:1;
bool is2G5:1;
bool isolated:1;
bool rate_police_egress:1;
bool rate_police_ingress:1;
@@ -886,6 +1011,7 @@ struct rtl838x_port {
u16 pvid;
bool eee_enabled;
enum phy_type phy;
struct phylink_pcs *pcs;
int led_set;
int leds_on_this_port;
struct rtldsa_counter_state counters;
@@ -1297,6 +1423,8 @@ struct rtldsa_config {
int n_counters;
int n_pie_blocks;
u8 port_ignore;
int trk_ctrl;
int trk_hash_ctrl;
void (*vlan_tables_read)(u32 vlan, struct rtl838x_vlan_info *info);
void (*vlan_set_tagged)(u32 vlan, struct rtl838x_vlan_info *info);
void (*vlan_set_untagged)(u32 vlan, u64 portmask);
@@ -1331,7 +1459,6 @@ struct rtldsa_config {
void (*write_l2_entry_using_hash)(u32 hash, u32 pos, struct rtl838x_l2_entry *e);
u64 (*read_cam)(int idx, struct rtl838x_l2_entry *e);
void (*write_cam)(int idx, struct rtl838x_l2_entry *e);
int (*trk_mbr_ctr)(int group);
int rma_bpdu_fld_pmask;
int spcl_trap_eapol_ctrl;
void (*init_eee)(struct rtl838x_switch_priv *priv, bool enable);
@@ -1362,10 +1489,26 @@ struct rtldsa_config {
void (*get_l3_router_mac)(u32 idx, struct rtl93xx_rt_mac *m);
void (*set_l3_router_mac)(u32 idx, struct rtl93xx_rt_mac *m);
void (*set_l3_egress_intf)(int idx, struct rtl838x_l3_intf *intf);
void (*set_distribution_algorithm)(int group, int algoidx, u32 algomask);
void (*set_receive_management_action)(int port, rma_ctrl_t type, action_type_t action);
void (*led_init)(struct rtl838x_switch_priv *priv);
void (*qos_init)(struct rtl838x_switch_priv *priv);
int (*trk_mbr_ctr)(int group);
void (*lag_switch_init)(struct rtl838x_switch_priv *priv);
void (*prepare_lag_fdb)(struct rtl838x_l2_entry *e, int lag_group);
int (*lag_set_port_members)(struct rtl838x_switch_priv *priv, int group, u64 members,
struct netdev_lag_upper_info *info);
int (*lag_setup_algomask)(struct rtl838x_switch_priv *priv, int group,
struct netdev_lag_upper_info *info);
int (*lag_set_distribution_algorithm)(struct rtl838x_switch_priv *priv,
int group, int algoidx,
u32 algomask);
void (*lag_set_local_group_id)(int local_group, int global_group, bool valid);
void (*lag_write_data)(u32 data[], struct rtldsa_93xx_lag_entry *e);
void (*lag_fill_data)(u32 data[], struct rtldsa_93xx_lag_entry *e);
void (*lag_set_local_port2group)(int group, int port, bool valid);
void (*lag_set_port2group)(int group, int port, bool valid);
struct table_reg* (*lag_table)(void);
void (*lag_sync_tables)(void);
};
struct rtl838x_switch_priv {
@@ -1374,8 +1517,7 @@ struct rtl838x_switch_priv {
struct device *dev;
u16 id;
u16 family_id;
struct rtl838x_port ports[57];
struct phylink_pcs *pcs[57];
struct rtldsa_port ports[57];
struct mutex reg_mutex; /* Mutex for individual register manipulations */
struct mutex pie_mutex; /* Mutex for Packet Inspection Engine */
int link_state_irq;
@@ -1440,6 +1582,13 @@ struct rtl838x_switch_priv {
void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv);
void rtl930x_dbgfs_init(struct rtl838x_switch_priv *priv);
void rtldsa_93xx_lag_switch_init(struct rtl838x_switch_priv *priv);
int rtldsa_93xx_lag_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
int group, int algoidx, u32 algomsk);
int rtldsa_93xx_lag_set_port_members(struct rtl838x_switch_priv *priv, int group,
u64 members, struct netdev_lag_upper_info *info);
void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group);
void rtldsa_counters_lock_register(struct rtl838x_switch_priv *priv, int port)
__acquires(&priv->ports[port].counters.lock);
@@ -1701,11 +1701,14 @@ static void rtl839x_set_egr_filter(int port, enum egr_filter state)
RTL839X_VLAN_PORT_EGR_FLTR + (((port >> 5) << 2)));
}
static void rtl839x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
static int rtldsa_839x_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
int group, int algoidx, u32 algomsk)
{
sw_w32_mask(3 << ((group & 0xf) << 1), algoidx << ((group & 0xf) << 1),
RTL839X_TRK_HASH_IDX_CTRL + ((group >> 4) << 2));
sw_w32(algomsk, RTL839X_TRK_HASH_CTRL + (algoidx << 2));
return 0;
}
static void rtl839x_set_receive_management_action(int port, rma_ctrl_t type, action_type_t action)
@@ -1728,6 +1731,20 @@ static void rtl839x_set_receive_management_action(int port, rma_ctrl_t type, act
}
}
static int rtldsa_839x_lag_set_port_members(struct rtl838x_switch_priv *priv, int group,
u64 members, struct netdev_lag_upper_info *info)
{
priv->lags_port_members[group] = members;
priv->r->set_port_reg_be(priv->lags_port_members[group],
priv->r->trk_mbr_ctr(group));
return 0;
}
int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
struct netdev_lag_upper_info *info);
const struct rtldsa_config rtldsa_839x_cfg = {
.mask_port_reg_be = rtl839x_mask_port_reg_be,
.set_port_reg_be = rtl839x_set_port_reg_be,
@@ -1813,7 +1830,9 @@ const struct rtldsa_config rtldsa_839x_cfg = {
.route_read = rtl839x_route_read,
.route_write = rtl839x_route_write,
.l3_setup = rtl839x_l3_setup,
.set_distribution_algorithm = rtl839x_set_distribution_algorithm,
.set_receive_management_action = rtl839x_set_receive_management_action,
.qos_init = rtldsa_839x_qos_init,
.lag_set_distribution_algorithm = rtldsa_839x_set_distribution_algorithm,
.lag_set_port_members = rtldsa_839x_lag_set_port_members,
.lag_setup_algomask = rtldsa_83xx_lag_setup_algomask,
};
@@ -127,6 +127,9 @@ inline u16 rtl_table_data(struct table_reg *r, int i);
inline u32 rtl_table_data_r(struct table_reg *r, int i);
inline void rtl_table_data_w(struct table_reg *r, u32 v, int i);
int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
struct netdev_lag_upper_info *info);
void rtldsa_838x_qos_init(struct rtl838x_switch_priv *priv);
void rtldsa_839x_qos_init(struct rtl838x_switch_priv *priv);
@@ -532,6 +532,118 @@ static void rtldsa_930x_enable_flood(int port, bool enable)
RTL930X_L2_LRN_PORT_CONSTRT_CTRL + port * 4);
}
static void rtldsa_930x_lag_set_port2group(int group, int port, bool valid)
{
struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 8);
u32 mask = valid ? RTL930X_SRC_TRK_MAP_TRK_VALID : 0;
rtl_table_read(r, port);
mask |= FIELD_PREP(RTL930X_SRC_TRK_MAP_TRK_ID, group); // Update TRK Field.
sw_w32(mask, rtl_table_data(r, 0));
rtl_table_write(r, port);
rtl_table_release(r);
}
/* Write data from the data buffer into the lag-entry strucure */
static void rtldsa_930x_lag_fill_data(u32 data[], struct rtldsa_93xx_lag_entry *e)
{
/* 95-64 */
e->num_tx_candi = FIELD_GET(RTL930X_LAG_NUM_TX_CANDI, data[0]);
e->l2_hash_mask_idx = FIELD_GET(RTL930X_LAG_L2_HASH_MSK_IDX, data[0]);
e->ip4_hash_mask_idx = FIELD_GET(RTL930X_LAG_IP4_HASH_MSK_IDX, data[0]);
e->ip6_hash_mask_idx = FIELD_GET(RTL930X_LAG_IP6_HASH_MSK_IDX, data[0]);
e->flood_dlf_bcast.sep_dlf_bcast_en = FIELD_GET(RTL930X_LAG_SEP_DLF_BCAST_EN, data[0]);
e->sep_kwn_mc_en = FIELD_GET(RTL930X_LAG_SEP_KWN_MC_EN, data[0]);
e->trk_dev7 = FIELD_GET(RTL930X_LAG_TRK_DEV7, data[0]);
e->trk_port7 = FIELD_GET(RTL930X_LAG_TRK_PORT7, data[0]);
e->trk_dev6 = FIELD_GET(RTL930X_LAG_TRK_DEV6, data[0]);
e->trk_port6 = FIELD_GET(RTL930X_LAG_TRK_PORT6, data[0]);
/* 63-32 */
e->trk_dev5 = FIELD_GET(RTL930X_LAG_TRK_DEV5, data[1]);
e->trk_port5 = FIELD_GET(RTL930X_LAG_TRK_PORT5, data[1]);
e->trk_dev4 = FIELD_GET(RTL930X_LAG_TRK_DEV4, data[1]);
e->trk_port4 = FIELD_GET(RTL930X_LAG_TRK_PORT4, data[1]);
e->trk_dev3 = FIELD_GET(RTL930X_LAG_TRK_DEV3, data[1]);
e->trk_port3 = FIELD_GET(RTL930X_LAG_TRK_PORT3, data[1]);
/* 31-0 */
e->trk_dev2 = FIELD_GET(RTL930X_LAG_TRK_DEV2, data[2]);
e->trk_port2 = FIELD_GET(RTL930X_LAG_TRK_PORT2, data[2]);
e->trk_dev1 = FIELD_GET(RTL930X_LAG_TRK_DEV1, data[2]);
e->trk_port1 = FIELD_GET(RTL930X_LAG_TRK_PORT1, data[2]);
e->trk_dev0 = FIELD_GET(RTL930X_LAG_TRK_DEV0, data[2]);
e->trk_port0 = FIELD_GET(RTL930X_LAG_TRK_PORT0, data[2]);
}
/* Write lag-entry data into buffer */
static void rtldsa_930x_lag_write_data(u32 data[], struct rtldsa_93xx_lag_entry *e)
{
/* 95-64 */
data[0] = FIELD_PREP(RTL930X_LAG_NUM_TX_CANDI, e->num_tx_candi);
data[0] |= FIELD_PREP(RTL930X_LAG_L2_HASH_MSK_IDX, e->l2_hash_mask_idx);
data[0] |= FIELD_PREP(RTL930X_LAG_IP4_HASH_MSK_IDX, e->ip4_hash_mask_idx);
data[0] |= FIELD_PREP(RTL930X_LAG_IP6_HASH_MSK_IDX, e->ip6_hash_mask_idx);
data[0] |= FIELD_PREP(RTL930X_LAG_SEP_DLF_BCAST_EN, e->flood_dlf_bcast.sep_dlf_bcast_en);
data[0] |= FIELD_PREP(RTL930X_LAG_SEP_KWN_MC_EN, e->sep_kwn_mc_en);
data[0] |= FIELD_PREP(RTL930X_LAG_TRK_DEV7, e->trk_dev7);
data[0] |= FIELD_PREP(RTL930X_LAG_TRK_PORT7, e->trk_port7);
data[0] |= FIELD_PREP(RTL930X_LAG_TRK_DEV6, e->trk_dev6);
data[0] |= FIELD_PREP(RTL930X_LAG_TRK_PORT6, e->trk_port6);
/* 63-32 */
data[1] = FIELD_PREP(RTL930X_LAG_TRK_DEV5, e->trk_dev5);
data[1] |= FIELD_PREP(RTL930X_LAG_TRK_PORT5, e->trk_port5);
data[1] |= FIELD_PREP(RTL930X_LAG_TRK_DEV4, e->trk_dev4);
data[1] |= FIELD_PREP(RTL930X_LAG_TRK_PORT4, e->trk_port4);
data[1] |= FIELD_PREP(RTL930X_LAG_TRK_DEV3, e->trk_dev3);
data[1] |= FIELD_PREP(RTL930X_LAG_TRK_PORT3, e->trk_port3);
/* 31-0 */
data[2] = FIELD_PREP(RTL930X_LAG_TRK_DEV2, e->trk_dev2);
data[2] |= FIELD_PREP(RTL930X_LAG_TRK_PORT2, e->trk_port2);
data[2] |= FIELD_PREP(RTL930X_LAG_TRK_DEV1, e->trk_dev1);
data[2] |= FIELD_PREP(RTL930X_LAG_TRK_PORT1, e->trk_port1);
data[2] |= FIELD_PREP(RTL930X_LAG_TRK_DEV0, e->trk_dev0);
data[2] |= FIELD_PREP(RTL930X_LAG_TRK_PORT0, e->trk_port0);
}
static void rtldsa_930x_lag_set_local_group_id(int local_group, int global_group, bool valid)
{
u32 mask = 0;
mask |= valid ? RTL930X_TRK_ID_CTRL_TRK_VALID : 0;
mask |= FIELD_PREP(RTL930X_TRK_ID_CTRL_TRK_ID, global_group);
sw_w32(mask, RTL930X_TRK_ID_CTRL + (4 * local_group));
}
static void rtldsa_930x_lag_set_local_port2group(int group, int port, bool valid)
{
u32 mask = 0;
mask |= valid ? RTL930X_LOCAL_PORT_TRK_MAP_IS_TRK_MBR : 0;
mask |= FIELD_PREP(RTL930X_LOCAL_PORT_TRK_MAP_TRK_ID, group);
sw_w32(mask, RTL930X_LOCAL_PORT_TRK_MAP + (4 * port));
}
static void rtldsa_930x_lag_sync_tables(void)
{
u32 val;
int ret;
sw_w32(BIT(0), RTL930X_TRK_LOCAL_TBL_REFRESH);
ret = readx_poll_timeout(sw_r32, RTL930X_TRK_LOCAL_TBL_REFRESH, val,
!(val & BIT(0)), 20, 10000);
if (ret)
pr_err("%s: timeout\n", __func__);
}
static struct table_reg *rtldsa_930x_lag_table(void)
{
return rtl_table_get(RTL9300_TBL_0, 7);
}
static int rtldsa_930x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, int port, u32 port_state[])
{
int idx = 1 - ((port + 3) / 16);
@@ -2513,46 +2625,6 @@ static void rtl930x_set_egr_filter(int port, enum egr_filter state)
RTL930X_VLAN_PORT_EGR_FLTR + (((port / 29) << 2)));
}
static void rtl930x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
{
u32 l3shift = 0;
u32 newmask = 0;
/* TODO: for now we set algoidx to 0 */
algoidx = 0;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SIP_BIT) {
l3shift = 4;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SIP_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DIP_BIT) {
l3shift = 4;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DIP_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) {
l3shift = 4;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) {
l3shift = 4;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT;
}
if (l3shift == 4) {
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SMAC_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DMAC_BIT;
} else {
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L2_DMAC_BIT;
}
sw_w32(newmask << l3shift, RTL930X_TRK_HASH_CTRL + (algoidx << 2));
}
static void rtldsa_930x_led_get_forced(const struct device_node *node,
const u8 leds_in_set[4],
u8 forced_leds_per_port[RTL930X_CPU_PORT])
@@ -2637,7 +2709,7 @@ static void rtl930x_led_init(struct rtl838x_switch_priv *priv)
sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_FIB_SET_SEL_CTRL(i));
sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_COPR_SET_SEL_CTRL(i));
if (!priv->ports[i].phy && !priv->pcs[i] && !(forced_leds_per_port[i]))
if (!priv->ports[i].phy && !priv->ports[i].pcs && !(forced_leds_per_port[i]))
continue;
if (forced_leds_per_port[i] > 0)
@@ -2835,10 +2907,22 @@ const struct rtldsa_config rtldsa_930x_cfg = {
.set_l3_router_mac = rtl930x_set_l3_router_mac,
.set_l3_egress_intf = rtl930x_set_l3_egress_intf,
#endif
.set_distribution_algorithm = rtl930x_set_distribution_algorithm,
.led_init = rtl930x_led_init,
.enable_learning = rtldsa_930x_enable_learning,
.enable_flood = rtldsa_930x_enable_flood,
.set_receive_management_action = rtldsa_930x_set_receive_management_action,
.qos_init = rtldsa_930x_qos_init,
.trk_ctrl = RTL930X_TRK_CTRL,
.trk_hash_ctrl = RTL930X_TRK_HASH_CTRL,
.prepare_lag_fdb = rtldsa_93xx_prepare_lag_fdb,
.lag_switch_init = rtldsa_93xx_lag_switch_init,
.lag_set_port_members = rtldsa_93xx_lag_set_port_members,
.lag_set_distribution_algorithm = rtldsa_93xx_lag_set_distribution_algorithm,
.lag_set_local_group_id = rtldsa_930x_lag_set_local_group_id,
.lag_write_data = rtldsa_930x_lag_write_data,
.lag_fill_data = rtldsa_930x_lag_fill_data,
.lag_set_local_port2group = rtldsa_930x_lag_set_local_port2group,
.lag_set_port2group = rtldsa_930x_lag_set_port2group,
.lag_sync_tables = rtldsa_930x_lag_sync_tables,
.lag_table = rtldsa_930x_lag_table,
};
@@ -1624,46 +1624,6 @@ static void rtl931x_set_egr_filter(int port, enum egr_filter state)
RTL931X_VLAN_PORT_EGR_FLTR + (((port >> 5) << 2)));
}
static void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
{
u32 l3shift = 0;
u32 newmask = 0;
/* TODO: for now we set algoidx to 0 */
algoidx = 0;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SIP_BIT) {
l3shift = 4;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SIP_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DIP_BIT) {
l3shift = 4;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DIP_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) {
l3shift = 4;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT;
}
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) {
l3shift = 4;
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT;
}
if (l3shift == 4) {
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SMAC_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DMAC_BIT;
} else {
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT)
newmask |= TRUNK_DISTRIBUTION_ALGO_L2_DMAC_BIT;
}
sw_w32(newmask << l3shift, RTL931X_TRK_HASH_CTRL + (algoidx << 2));
}
static void rtldsa_931x_led_get_forced(const struct device_node *node,
const u8 leds_in_set[4],
u8 forced_leds_per_port[RTL931X_CPU_PORT])
@@ -1749,7 +1709,7 @@ static void rtldsa_931x_led_init(struct rtl838x_switch_priv *priv)
sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_COPR_SET_SEL_CTRL(i));
/* Skip port if not present (auto-detect) or not in forced mask */
if (!priv->ports[i].phy && !priv->pcs[i] && !(forced_leds_per_port[i]))
if (!priv->ports[i].phy && !priv->ports[i].pcs && !(forced_leds_per_port[i]))
continue;
if (forced_leds_per_port[i] > 0)
@@ -1785,6 +1745,123 @@ static void rtldsa_931x_led_init(struct rtl838x_switch_priv *priv)
dev_dbg(dev, "%08x: %08x\n", 0xbb000600 + i * 4, sw_r32(0x0600 + i * 4));
}
static void rtldsa_931x_lag_set_port2group(int group, int port, bool valid)
{
u32 trk_id_valid = valid ? RTL931X_SRC_TRK_MAP_TRK_ID_VALID : 0;
struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 13);
u32 mask = 0;
rtl_table_read(r, port);
mask |= trk_id_valid;
/* Update TRK Field */
mask |= FIELD_PREP(RTL931X_SRC_TRK_MAP_TRK_ID, group);
sw_w32(mask, rtl_table_data(r, 0));
rtl_table_write(r, port);
rtl_table_release(r);
}
/* Write data from the data buffer into the lag-entry strucure */
static void rtldsa_931x_lag_fill_data(u32 data[], struct rtldsa_93xx_lag_entry *e)
{
/* 95-64 */
e->num_tx_candi = FIELD_GET(RTL931X_LAG_NUM_TX_CANDI, data[0]);
e->l2_hash_mask_idx = FIELD_GET(RTL931X_LAG_L2_HASH_MSK_IDX, data[0]);
e->ip4_hash_mask_idx = FIELD_GET(RTL931X_LAG_IP4_HASH_MSK_IDX, data[0]);
e->ip6_hash_mask_idx = FIELD_GET(RTL931X_LAG_IP6_HASH_MSK_IDX, data[0]);
e->flood_dlf_bcast.sep_flood_en = FIELD_GET(RTL931X_LAG_SEP_FLOOD_EN, data[0]);
e->sep_kwn_mc_en = FIELD_GET(RTL931X_LAG_SEP_KWN_MC_EN, data[0]);
e->trk_dev7 = FIELD_GET(RTL931X_LAG_TRK_DEV7, data[0]);
e->trk_port7 = FIELD_GET(RTL931X_LAG_TRK_PORT7, data[0]);
e->trk_dev6 = FIELD_GET(RTL931X_LAG_TRK_DEV6, data[0]);
e->trk_port6 = FIELD_GET(RTL931X_LAG_TRK_PORT6, data[0]);
/* 63-32 */
e->trk_dev5 = FIELD_GET(RTL931X_LAG_TRK_DEV5, data[1]);
e->trk_port5 = FIELD_GET(RTL931X_LAG_TRK_PORT5, data[1]);
e->trk_dev4 = FIELD_GET(RTL931X_LAG_TRK_DEV4, data[1]);
e->trk_port4 = FIELD_GET(RTL931X_LAG_TRK_PORT4, data[1]);
e->trk_dev3 = FIELD_GET(RTL931X_LAG_TRK_DEV3, data[1]);
e->trk_port3 = FIELD_GET(RTL931X_LAG_TRK_PORT3, data[1]);
/* 31-0 */
e->trk_dev2 = FIELD_GET(RTL931X_LAG_TRK_DEV2, data[2]);
e->trk_port2 = FIELD_GET(RTL931X_LAG_TRK_PORT2, data[2]);
e->trk_dev1 = FIELD_GET(RTL931X_LAG_TRK_DEV1, data[2]);
e->trk_port1 = FIELD_GET(RTL931X_LAG_TRK_PORT1, data[2]);
e->trk_dev0 = FIELD_GET(RTL931X_LAG_TRK_DEV0, data[2]);
e->trk_port0 = FIELD_GET(RTL931X_LAG_TRK_PORT0, data[2]);
}
/* Write lag-entry data into buffer */
static void rtldsa_931x_lag_write_data(u32 data[], struct rtldsa_93xx_lag_entry *e)
{
/* 95-64 */
data[0] = FIELD_PREP(RTL931X_LAG_NUM_TX_CANDI, e->num_tx_candi);
data[0] |= FIELD_PREP(RTL931X_LAG_L2_HASH_MSK_IDX, e->l2_hash_mask_idx);
data[0] |= FIELD_PREP(RTL931X_LAG_IP4_HASH_MSK_IDX, e->ip4_hash_mask_idx);
data[0] |= FIELD_PREP(RTL931X_LAG_IP6_HASH_MSK_IDX, e->ip6_hash_mask_idx);
data[0] |= FIELD_PREP(RTL931X_LAG_SEP_FLOOD_EN, e->flood_dlf_bcast.sep_flood_en);
data[0] |= FIELD_PREP(RTL931X_LAG_SEP_KWN_MC_EN, e->sep_kwn_mc_en);
data[0] |= FIELD_PREP(RTL931X_LAG_TRK_DEV7, e->trk_dev7);
data[0] |= FIELD_PREP(RTL931X_LAG_TRK_PORT7, e->trk_port7);
data[0] |= FIELD_PREP(RTL931X_LAG_TRK_DEV6, e->trk_dev6);
data[0] |= FIELD_PREP(RTL931X_LAG_TRK_PORT6, e->trk_port6);
/* 63-32 */
data[1] = FIELD_PREP(RTL931X_LAG_TRK_DEV5, e->trk_dev5);
data[1] |= FIELD_PREP(RTL931X_LAG_TRK_PORT5, e->trk_port5);
data[1] |= FIELD_PREP(RTL931X_LAG_TRK_DEV4, e->trk_dev4);
data[1] |= FIELD_PREP(RTL931X_LAG_TRK_PORT4, e->trk_port4);
data[1] |= FIELD_PREP(RTL931X_LAG_TRK_DEV3, e->trk_dev3);
data[1] |= FIELD_PREP(RTL931X_LAG_TRK_PORT3, e->trk_port3);
/* 31-0 */
data[2] = FIELD_PREP(RTL931X_LAG_TRK_DEV2, e->trk_dev2);
data[2] |= FIELD_PREP(RTL931X_LAG_TRK_PORT2, e->trk_port2);
data[2] |= FIELD_PREP(RTL931X_LAG_TRK_DEV1, e->trk_dev1);
data[2] |= FIELD_PREP(RTL931X_LAG_TRK_PORT1, e->trk_port1);
data[2] |= FIELD_PREP(RTL931X_LAG_TRK_DEV0, e->trk_dev0);
data[2] |= FIELD_PREP(RTL931X_LAG_TRK_PORT0, e->trk_port0);
}
static void rtldsa_931x_lag_set_local_group_id(int local_group, int global_group, bool valid)
{
u32 mask = 0;
mask |= valid ? RTL931X_TRK_ID_CTRL_TRK_VALID : 0;
mask |= FIELD_PREP(RLT931X_TRK_ID_CTRL_TRK_ID, global_group);
sw_w32(mask, RTL931X_TRK_ID_CTRL + (4 * local_group));
}
static void rtldsa_931x_lag_set_local_port2group(int group, int port, bool valid)
{
u32 mask = 0;
mask |= valid ? RTL931X_LOCAL_PORT_TRK_MAP_IS_TRK_MBR : 0;
mask |= FIELD_PREP(RTL931X_LOCAL_PORT_TRK_MAP_TRK_ID, group);
sw_w32(mask, RTL931X_LOCAL_PORT_TRK_MAP + (4 * port));
}
static void rtldsa_931x_lag_sync_tables(void)
{
u32 val;
int ret;
sw_w32(BIT(0), RTL931X_TRK_LOCAL_TBL_REFRESH);
ret = readx_poll_timeout(sw_r32, RTL931X_TRK_LOCAL_TBL_REFRESH, val,
!(val & BIT(0)), 20, 10000);
if (ret)
pr_err("%s: timeout\n", __func__);
}
static struct table_reg *rtldsa_931x_lag_table(void)
{
return rtl_table_get(RTL9310_TBL_2, 0);
}
static u64 rtldsa_931x_stat_port_table_read(int port, unsigned int mib_size,
unsigned int mib_offset, bool is_pvt)
{
@@ -1950,7 +2027,6 @@ const struct rtldsa_config rtldsa_931x_cfg = {
.rma_bpdu_fld_pmask = RTL931X_RMA_BPDU_FLD_PMSK,
.set_vlan_igr_filter = rtl931x_set_igr_filter,
.set_vlan_egr_filter = rtl931x_set_egr_filter,
.set_distribution_algorithm = rtl931x_set_distribution_algorithm,
.l2_hash_key = rtl931x_l2_hash_key,
.l2_hash_seed = rtldsa_931x_l2_hash_seed,
.read_mcast_pmask = rtl931x_read_mcast_pmask,
@@ -1965,4 +2041,17 @@ const struct rtldsa_config rtldsa_931x_cfg = {
.enable_flood = rtldsa_931x_enable_flood,
.set_receive_management_action = rtldsa_931x_set_receive_management_action,
.qos_init = rtldsa_931x_qos_init,
.trk_ctrl = RTL931X_TRK_CTRL,
.trk_hash_ctrl = RTL931X_TRK_HASH_CTRL,
.prepare_lag_fdb = rtldsa_93xx_prepare_lag_fdb,
.lag_switch_init = rtldsa_93xx_lag_switch_init,
.lag_set_port_members = rtldsa_93xx_lag_set_port_members,
.lag_set_distribution_algorithm = rtldsa_93xx_lag_set_distribution_algorithm,
.lag_set_local_group_id = rtldsa_931x_lag_set_local_group_id,
.lag_write_data = rtldsa_931x_lag_write_data,
.lag_fill_data = rtldsa_931x_lag_fill_data,
.lag_set_local_port2group = rtldsa_931x_lag_set_local_port2group,
.lag_set_port2group = rtldsa_931x_lag_set_port2group,
.lag_sync_tables = rtldsa_931x_lag_sync_tables,
.lag_table = rtldsa_931x_lag_table,
};
@@ -28,7 +28,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19501,6 +19501,12 @@ S: Maintained
@@ -19507,6 +19507,12 @@ S: Maintained
F: Documentation/devicetree/bindings/net/dsa/realtek.yaml
F: drivers/net/dsa/realtek/*
@@ -22,7 +22,7 @@ Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20158,6 +20158,13 @@ S: Maintained
@@ -20164,6 +20164,13 @@ S: Maintained
T: git https://github.com/pkshih/rtw.git
F: drivers/net/wireless/realtek/rtl8xxxu/
@@ -0,0 +1,67 @@
From 0c741b8b6963e584b41c284cd743c545636edb04 Mon Sep 17 00:00:00 2001
From: Ahmed Naseef <naseefkm@gmail.com>
Date: Sat, 7 Feb 2026 11:02:43 +0400
Subject: mtd: nand: realtek-ecc: relax OOB size check to minimum
The ECC engine strictly validates that flash OOB size equals exactly
64 bytes. However, some NAND chips have a larger physical OOB while
vendor firmware only uses the first 64 bytes for the ECC layout. For
example the Macronix MX35LF1G24AD found in the Netlink HG323DAC has
128 byte physical OOB but vendor firmware only uses the first 64
bytes (24 bytes free + 40 bytes BCH6 parity), leaving bytes 64-127
unused.
Since the engine only operates on the first 64 bytes of OOB
regardless of the physical size, change the check from exact match
to minimum size. Flash with OOB >= 64 bytes works correctly with
the engine's 64-byte layout.
Suggested-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Signed-off-by: Ahmed Naseef <naseefkm@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/ecc-realtek.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
--- a/drivers/mtd/nand/ecc-realtek.c
+++ b/drivers/mtd/nand/ecc-realtek.c
@@ -17,10 +17,12 @@
* - BCH12 : Generate 20 ECC bytes from 512 data bytes plus 6 free bytes
*
* It can run for arbitrary NAND flash chips with different block and OOB sizes. Currently there
- * are only two known devices in the wild that have NAND flash and make use of this ECC engine
- * (Linksys LGS328C & LGS352C). To keep compatibility with vendor firmware, new modes can only
- * be added when new data layouts have been analyzed. For now allow BCH6 on flash with 2048 byte
- * blocks and 64 bytes oob.
+ * are a few known devices in the wild that make use of this ECC engine
+ * (Linksys LGS328C, LGS352C & Netlink HG323DAC). To keep compatibility with vendor firmware,
+ * new modes can only be added when new data layouts have been analyzed. For now allow BCH6 on
+ * flash with 2048 byte blocks and at least 64 bytes oob. Some vendors make use of
+ * 128 bytes OOB NAND chips (e.g. Macronix MX35LF1G24AD) but only use BCH6 and thus the first
+ * 64 bytes of the OOB area. In this case the engine leaves any extra bytes unused.
*
* This driver aligns with kernel ECC naming conventions. Neverthless a short notice on the
* Realtek naming conventions for the different structures in the OOB area.
@@ -39,7 +41,7 @@
*/
#define RTL_ECC_ALLOWED_PAGE_SIZE 2048
-#define RTL_ECC_ALLOWED_OOB_SIZE 64
+#define RTL_ECC_ALLOWED_MIN_OOB_SIZE 64
#define RTL_ECC_ALLOWED_STRENGTH 6
#define RTL_ECC_BLOCK_SIZE 512
@@ -310,10 +312,10 @@ static int rtl_ecc_check_support(struct
struct mtd_info *mtd = nanddev_to_mtd(nand);
struct device *dev = nand->ecc.engine->dev;
- if (mtd->oobsize != RTL_ECC_ALLOWED_OOB_SIZE ||
+ if (mtd->oobsize < RTL_ECC_ALLOWED_MIN_OOB_SIZE ||
mtd->writesize != RTL_ECC_ALLOWED_PAGE_SIZE) {
- dev_err(dev, "only flash geometry data=%d, oob=%d supported\n",
- RTL_ECC_ALLOWED_PAGE_SIZE, RTL_ECC_ALLOWED_OOB_SIZE);
+ dev_err(dev, "only flash geometry data=%d, oob>=%d supported\n",
+ RTL_ECC_ALLOWED_PAGE_SIZE, RTL_ECC_ALLOWED_MIN_OOB_SIZE);
return -EINVAL;
}
@@ -0,0 +1,52 @@
From linux-i2c Fri Feb 27 11:11:34 2026
From: Jan Kantert <jan-kernel () kantert ! net>
Date: Fri, 27 Feb 2026 11:11:34 +0000
To: linux-i2c
Subject: [PATCH] i2c: rtl9300: add support for 50 kHz and 2.5 MHz bus speeds
Message-Id: <20260227111134.2163701-1-jan-kernel () kantert ! net>
X-MARC-Message: https://marc.info/?l=linux-i2c&m=177219358420283
Some SFP modules on certain switches (for example the ONTi ONT-S508CL-8S and
XikeStor SKS8300-8X) exhibit unreliable I2C communication at the currently
supported speeds. Add support for 50 kHz and 2.5 MHz I2C bus modes on the
RTL9300 to improve compatibility with these devices.
Signed-off-by: Jan Kantert <jan-kernel@kantert.net>
---
drivers/i2c/busses/i2c-rtl9300.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -11,10 +11,16 @@
#include <linux/unaligned.h>
enum rtl9300_bus_freq {
- RTL9300_I2C_STD_FREQ,
- RTL9300_I2C_FAST_FREQ,
+ RTL9300_I2C_STD_FREQ, // 100kHz
+ RTL9300_I2C_FAST_FREQ, // 400kHz
+ RTL9300_I2C_SUPER_FAST_FREQ, // 2.5MHz
+ RTL9300_I2C_SLOW_FREQ, // 50kHz
};
+#define RTL9300_I2C_MAX_SUPER_FAST_FREQ 2500000
+#define RTL9300_I2C_MAX_SLOW_FREQ 50000
+
+
struct rtl9300_i2c;
struct rtl9300_i2c_chan {
@@ -434,6 +440,12 @@ static int rtl9300_i2c_probe(struct plat
case I2C_MAX_FAST_MODE_FREQ:
chan->bus_freq = RTL9300_I2C_FAST_FREQ;
break;
+ case RTL9300_I2C_MAX_SUPER_FAST_FREQ:
+ chan->bus_freq = RTL9300_I2C_SUPER_FAST_FREQ;
+ break;
+ case RTL9300_I2C_MAX_SLOW_FREQ:
+ chan->bus_freq = RTL9300_I2C_SLOW_FREQ;
+ break;
default:
dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
sda_num, clock_freq);
@@ -10,7 +10,7 @@ Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -718,10 +718,64 @@ static int sfp_i2c_write(struct sfp *sfp
@@ -724,10 +724,64 @@ static int sfp_i2c_write(struct sfp *sfp
return ret == ARRAY_SIZE(msgs) ? len : 0;
}
@@ -77,7 +77,7 @@ Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
sfp->i2c = i2c;
sfp->read = sfp_i2c_read;
@@ -753,6 +807,29 @@ static int sfp_i2c_mdiobus_create(struct
@@ -759,6 +813,29 @@ static int sfp_i2c_mdiobus_create(struct
return 0;
}
@@ -107,7 +107,7 @@ Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
{
mdiobus_unregister(sfp->i2c_mii);
@@ -1927,9 +2004,15 @@ static void sfp_sm_fault(struct sfp *sfp
@@ -1933,9 +2010,15 @@ static void sfp_sm_fault(struct sfp *sfp
static int sfp_sm_add_mdio_bus(struct sfp *sfp)
{
@@ -20,7 +20,7 @@ Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22072,7 +22072,7 @@ STARFIVE JH71X0 RESET CONTROLLER DRIVERS
@@ -22078,7 +22078,7 @@ STARFIVE JH71X0 RESET CONTROLLER DRIVERS
M: Emil Renner Berthing <kernel@esmil.dk>
M: Hal Feng <hal.feng@starfivetech.com>
S: Maintained
+3 -3
View File
@@ -11,9 +11,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/firmware-utils.git
PKG_SOURCE_DATE:=2025-11-11
PKG_SOURCE_VERSION:=c42a3bc53da869d02c8ae4d62b3b08a95ff5833f
PKG_MIRROR_HASH:=c9cbe9aafc3476dac9d9bd1b26f932048f895bce775e8220f82fae097463c539
PKG_SOURCE_DATE:=2026-03-05
PKG_SOURCE_VERSION:=6a87eaf434cb89d4eba0b811a4b5d158fd9c519f
PKG_MIRROR_HASH:=b40d6b02dc896359e413dd2ae9d0d616b5c1270dd1eb825b317d27fa531582e2
include $(INCLUDE_DIR)/host-build.mk
include $(INCLUDE_DIR)/cmake.mk