diff --git a/board/aarch64/linux_defconfig b/board/aarch64/linux_defconfig index 054a13d6..f6efbf0d 100644 --- a/board/aarch64/linux_defconfig +++ b/board/aarch64/linux_defconfig @@ -34,6 +34,10 @@ CONFIG_PROFILING=y CONFIG_ARCH_SPARX5=y CONFIG_ARCH_MVEBU=y CONFIG_ARCH_VEXPRESS=y +CONFIG_ARM64_ERRATUM_2441007=y +CONFIG_ARM64_ERRATUM_1286807=y +CONFIG_ARM64_ERRATUM_1542419=y +CONFIG_ARM64_ERRATUM_2441009=y CONFIG_ARM64_VA_BITS_48=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=64 @@ -57,6 +61,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_KSM=y CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_CMA=y +CONFIG_CMA_AREAS=7 CONFIG_NET=y CONFIG_PACKET=y CONFIG_XDP_SOCKETS=y @@ -165,7 +170,6 @@ CONFIG_BRIDGE_EBT_REDIRECT=m CONFIG_BRIDGE_EBT_SNAT=m CONFIG_BRIDGE_EBT_LOG=m CONFIG_BRIDGE_EBT_NFLOG=m -CONFIG_BPFILTER=y CONFIG_BRIDGE=y CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_BRIDGE_MRP=y @@ -227,6 +231,7 @@ CONFIG_SCSI_SAS_ATA=y CONFIG_SCSI_VIRTIO=y CONFIG_ATA=y CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 CONFIG_SATA_AHCI_PLATFORM=y CONFIG_AHCI_MVEBU=y CONFIG_PATA_OF_PLATFORM=y @@ -282,6 +287,7 @@ CONFIG_NET_DSA_MV88E6XXX_PTP=y CONFIG_MVNETA=m CONFIG_MVPP2=m # CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_META is not set # CONFIG_NET_VENDOR_MICREL is not set CONFIG_SPARX5_SWITCH=y # CONFIG_NET_VENDOR_MICROSEMI is not set @@ -353,13 +359,14 @@ CONFIG_SERIAL_XILINX_PS_UART=y CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y CONFIG_SERIAL_MVEBU_UART=y CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM_CN10K=m CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MUX=y CONFIG_I2C_MUX_GPIO=y CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_MUX_PINCTRL=y -CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_DESIGNWARE_CORE=y CONFIG_I2C_MV64XXX=y CONFIG_I2C_SLAVE=y CONFIG_SPI=y @@ -495,6 +502,7 @@ CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_TI_ADC081C=y CONFIG_PWM=y +CONFIG_RESET_GPIO=y CONFIG_PHY_MVEBU_CP110_COMPHY=y CONFIG_PHY_MVEBU_CP110_UTMI=y CONFIG_PHY_SAMSUNG_USB2=y @@ -523,13 +531,13 @@ CONFIG_9P_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_SECURITY=y +CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,bpf" CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_GHASH_ARM64_CE=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y CONFIG_CRYPTO_AES_ARM64_CE_CCM=y CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=0 diff --git a/board/x86_64/linux_defconfig b/board/x86_64/linux_defconfig index 25fa755b..c2e05ac1 100644 --- a/board/x86_64/linux_defconfig +++ b/board/x86_64/linux_defconfig @@ -145,7 +145,6 @@ CONFIG_BRIDGE_EBT_REDIRECT=m CONFIG_BRIDGE_EBT_SNAT=m CONFIG_BRIDGE_EBT_LOG=m CONFIG_BRIDGE_EBT_NFLOG=m -CONFIG_BPFILTER=y CONFIG_BRIDGE=y CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_BRIDGE_MRP=y diff --git a/configs/aarch64_defconfig b/configs/aarch64_defconfig index 1b505875..6564f038 100644 --- a/configs/aarch64_defconfig +++ b/configs/aarch64_defconfig @@ -27,13 +27,9 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh" BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_VERSION=y -BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.52" +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.1" BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig" -BR2_LINUX_KERNEL_DTS_SUPPORT=y -BR2_LINUX_KERNEL_INTREE_DTS_NAME="alder/alder styx/dcp-sc-28p-a styx/dcp-sc-28p-b marvell/armada-3720-espressobin marvell/armada-3720-espressobin-emmc marvell/armada-3720-espressobin-v7 marvell/armada-3720-espressobin-v7-emmc marvell/armada-3720-espressobin-ultra marvell/cn9130-crb-A marvell/cn9130-crb-B microchip/sparx5_pcb135_emmc_no_psci" -BR2_LINUX_KERNEL_CUSTOM_DTS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/dts" -BR2_LINUX_KERNEL_DTB_KEEP_DIRNAME=y BR2_LINUX_KERNEL_INSTALL_TARGET=y BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig" BR2_PACKAGE_STRACE=y @@ -130,6 +126,10 @@ INFIX_DESC="Infix is a Network Operating System based on Linux. It can be set u INFIX_HOME="https://github.com/kernelkit/infix/" INFIX_DOC="https://github.com/kernelkit/infix/tree/main/doc" INFIX_SUPPORT="mailto:kernelkit@googlegroups.com" +BR2_PACKAGE_ALDER_ALDER=y +BR2_PACKAGE_MARVELL_CN9130_CRB=y +BR2_PACKAGE_MARVELL_ESPRESSOBIN=y +BR2_PACKAGE_STYX_DCP_SC_28P=y BR2_PACKAGE_CONFD=y BR2_PACKAGE_CONFD_TEST_MODE=y BR2_PACKAGE_CURIOS_HTTPD=y diff --git a/configs/aarch64_minimal_defconfig b/configs/aarch64_minimal_defconfig index 736c64d0..63b491f2 100644 --- a/configs/aarch64_minimal_defconfig +++ b/configs/aarch64_minimal_defconfig @@ -27,13 +27,9 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh" BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_VERSION=y -BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.52" +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.1" BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig" -BR2_LINUX_KERNEL_DTS_SUPPORT=y -BR2_LINUX_KERNEL_INTREE_DTS_NAME="alder/alder styx/dcp-sc-28p-a styx/dcp-sc-28p-b marvell/armada-3720-espressobin marvell/armada-3720-espressobin-emmc marvell/armada-3720-espressobin-v7 marvell/armada-3720-espressobin-v7-emmc marvell/armada-3720-espressobin-ultra marvell/cn9130-crb-A marvell/cn9130-crb-B microchip/sparx5_pcb135_emmc_no_psci" -BR2_LINUX_KERNEL_CUSTOM_DTS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/dts" -BR2_LINUX_KERNEL_DTB_KEEP_DIRNAME=y BR2_LINUX_KERNEL_INSTALL_TARGET=y BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig" BR2_PACKAGE_STRACE=y @@ -113,6 +109,10 @@ INFIX_DESC="Infix is a Network Operating System based on Linux. It can be set u INFIX_HOME="https://github.com/kernelkit/infix/" INFIX_DOC="https://github.com/kernelkit/infix/tree/main/doc" INFIX_SUPPORT="mailto:kernelkit@googlegroups.com" +BR2_PACKAGE_ALDER_ALDER=y +BR2_PACKAGE_MARVELL_CN9130_CRB=y +BR2_PACKAGE_MARVELL_ESPRESSOBIN=y +BR2_PACKAGE_STYX_DCP_SC_28P=y BR2_PACKAGE_CONFD=y BR2_PACKAGE_CONFD_TEST_MODE=y BR2_PACKAGE_GENCERT=y diff --git a/configs/x86_64_defconfig b/configs/x86_64_defconfig index 5ec8fde0..c82b0937 100644 --- a/configs/x86_64_defconfig +++ b/configs/x86_64_defconfig @@ -26,7 +26,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INF BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh" BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_VERSION=y -BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.52" +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.1" BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig" BR2_LINUX_KERNEL_INSTALL_TARGET=y diff --git a/configs/x86_64_minimal_defconfig b/configs/x86_64_minimal_defconfig index 9d6ca50f..0f3b70c9 100644 --- a/configs/x86_64_minimal_defconfig +++ b/configs/x86_64_minimal_defconfig @@ -26,7 +26,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INF BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh" BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_VERSION=y -BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.52" +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.1" BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig" BR2_LINUX_KERNEL_INSTALL_TARGET=y diff --git a/package/Config.in b/package/Config.in index b3899562..4fe7dbd6 100644 --- a/package/Config.in +++ b/package/Config.in @@ -1,5 +1,9 @@ menu "Packages" +comment "Hardware Support" +source "$BR2_EXTERNAL_INFIX_PATH/package/board/Config.in" + +comment "Software Packages" source "$BR2_EXTERNAL_INFIX_PATH/package/bin/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/confd/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/confd-test-mode/Config.in" diff --git a/package/board/Config.in b/package/board/Config.in new file mode 100644 index 00000000..ebeff591 --- /dev/null +++ b/package/board/Config.in @@ -0,0 +1,9 @@ +menu "Boards" + +source "$BR2_EXTERNAL_INFIX_PATH/package/board/alder-alder/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/package/board/marvell-cn9130-crb/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/package/board/marvell-espressobin/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/package/board/microchip-sparx5-pcb135/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/package/board/styx-dcp-sc-28p/Config.in" + +endmenu diff --git a/package/board/alder-alder/Config.in b/package/board/alder-alder/Config.in new file mode 100644 index 00000000..12a19e1d --- /dev/null +++ b/package/board/alder-alder/Config.in @@ -0,0 +1,5 @@ +config BR2_PACKAGE_ALDER_ALDER + bool "Alder" + depends on BR2_aarch64 + help + Alder diff --git a/package/board/alder-alder/alder-alder.mk b/package/board/alder-alder/alder-alder.mk new file mode 100644 index 00000000..41f6f7fd --- /dev/null +++ b/package/board/alder-alder/alder-alder.mk @@ -0,0 +1,2 @@ +$(eval $(ix-board)) +$(eval $(generic-package)) diff --git a/package/board/board.mk b/package/board/board.mk new file mode 100644 index 00000000..5a20eef0 --- /dev/null +++ b/package/board/board.mk @@ -0,0 +1,53 @@ +define inner-ix-board + +$(2)_VERSION = ix-board +$(2)_LICENSE = BSD-3-Clause +$(2)_LICENSE_FILES = LICENSE +$(2)_SITE_METHOD = local +$(2)_SITE = $$(BR2_EXTERNAL_INFIX_PATH)/src/board/$(1) +$(2)_REDISTRIBUTE = NO + +# The kernel must be built first. +$(2)_DEPENDENCIES += \ + linux \ + $$(BR2_MAKE_HOST_DEPENDENCY) + +# This is only defined in some infrastructures (e.g. autotools, cmake), +# but not in others (e.g. generic). So define it here as well. +$(2)_MAKE ?= $$(BR2_MAKE) + +define $(2)_DTBS_BUILD + @$$(call MESSAGE,"Building device tree blob(s)") + $$(LINUX_MAKE_ENV) $$($$(PKG)_MAKE) \ + -C $$(LINUX_DIR) \ + $$(LINUX_MAKE_FLAGS) \ + $$($(2)_DTB_MAKE_OPTS) \ + PWD=$$(@D)/dts \ + M=$$(@D)/dts \ + modules +endef +$(2)_POST_BUILD_HOOKS += $(2)_DTBS_BUILD + +define $(2)_DTBS_INSTALL_TARGET + @$$(call MESSAGE,"Installing device tree blob(s)") + $$(TARGET_MAKE_ENV) $$(TARGET_CONFIGURE_OPTS) $$($$(PKG)_MAKE) \ + -f $$(BR2_EXTERNAL_INFIX_PATH)/package/board/dtb-inst.makefile \ + -C $$(@D)/dts \ + DESTDIR="$$(TARGET_DIR)" \ + install +endef +$(2)_POST_INSTALL_TARGET_HOOKS += $(2)_DTBS_INSTALL_TARGET + +define $(2)_OVERLAY_INSTALL_TARGET + @test -d $$(@D)/rootfs && \ + $$(call MESSAGE,"Copying overlay") && \ + $$(call SYSTEM_RSYNC,$$(@D)/rootfs,$(TARGET_DIR)) || \ + true +endef +$(2)_POST_INSTALL_TARGET_HOOKS += $(2)_OVERLAY_INSTALL_TARGET + +endef + +ix-board = $(call inner-ix-board,$(pkgname),$(call UPPERCASE,$(pkgname))) + +include $(sort $(wildcard $(BR2_EXTERNAL_INFIX_PATH)/package/board/*/*.mk)) diff --git a/package/board/dtb-inst.makefile b/package/board/dtb-inst.makefile new file mode 100644 index 00000000..62b0f059 --- /dev/null +++ b/package/board/dtb-inst.makefile @@ -0,0 +1,9 @@ +include Makefile + +install: $(addprefix $(DESTDIR)/boot/,$(dtb-y)) + +$(DESTDIR)/boot/%.dtb: %.dtb + @echo " DTB-INSTALL $<" + @install -D $< $@ + +.PHONY: install diff --git a/package/board/marvell-cn9130-crb/Config.in b/package/board/marvell-cn9130-crb/Config.in new file mode 100644 index 00000000..3ede2b83 --- /dev/null +++ b/package/board/marvell-cn9130-crb/Config.in @@ -0,0 +1,5 @@ +config BR2_PACKAGE_MARVELL_CN9130_CRB + bool "Marvell CN9130-CRB" + depends on BR2_aarch64 + help + Customer Reference Board for CN9130 diff --git a/package/board/marvell-cn9130-crb/marvell-cn9130-crb.mk b/package/board/marvell-cn9130-crb/marvell-cn9130-crb.mk new file mode 100644 index 00000000..41f6f7fd --- /dev/null +++ b/package/board/marvell-cn9130-crb/marvell-cn9130-crb.mk @@ -0,0 +1,2 @@ +$(eval $(ix-board)) +$(eval $(generic-package)) diff --git a/package/board/marvell-espressobin/Config.in b/package/board/marvell-espressobin/Config.in new file mode 100644 index 00000000..a8bed5f6 --- /dev/null +++ b/package/board/marvell-espressobin/Config.in @@ -0,0 +1,5 @@ +config BR2_PACKAGE_MARVELL_ESPRESSOBIN + bool "Marvell ESPRESSObin" + depends on BR2_aarch64 + help + Marvell ESPRESSObin diff --git a/package/board/marvell-espressobin/marvell-espressobin.mk b/package/board/marvell-espressobin/marvell-espressobin.mk new file mode 100644 index 00000000..41f6f7fd --- /dev/null +++ b/package/board/marvell-espressobin/marvell-espressobin.mk @@ -0,0 +1,2 @@ +$(eval $(ix-board)) +$(eval $(generic-package)) diff --git a/package/board/microchip-sparx5-pcb135/Config.in b/package/board/microchip-sparx5-pcb135/Config.in new file mode 100644 index 00000000..4cf7c8d0 --- /dev/null +++ b/package/board/microchip-sparx5-pcb135/Config.in @@ -0,0 +1,5 @@ +config BR2_PACKAGE_MICROCHIP_SPARX5_PCB135 + bool "Microchip SparX-5i PCB135" + depends on BR2_aarch64 + help + Microchip's evaluation board for SparX-5i diff --git a/package/board/microchip-sparx5-pcb135/microchip-sparx5-pcb135.mk b/package/board/microchip-sparx5-pcb135/microchip-sparx5-pcb135.mk new file mode 100644 index 00000000..41f6f7fd --- /dev/null +++ b/package/board/microchip-sparx5-pcb135/microchip-sparx5-pcb135.mk @@ -0,0 +1,2 @@ +$(eval $(ix-board)) +$(eval $(generic-package)) diff --git a/package/board/styx-dcp-sc-28p/Config.in b/package/board/styx-dcp-sc-28p/Config.in new file mode 100644 index 00000000..2fa8832b --- /dev/null +++ b/package/board/styx-dcp-sc-28p/Config.in @@ -0,0 +1,5 @@ +config BR2_PACKAGE_STYX_DCP_SC_28P + bool "Styx DCP-SC-28P" + depends on BR2_aarch64 + help + Styx DCP-SC-28P diff --git a/package/board/styx-dcp-sc-28p/styx-dcp-sc-28p.mk b/package/board/styx-dcp-sc-28p/styx-dcp-sc-28p.mk new file mode 100644 index 00000000..41f6f7fd --- /dev/null +++ b/package/board/styx-dcp-sc-28p/styx-dcp-sc-28p.mk @@ -0,0 +1,2 @@ +$(eval $(ix-board)) +$(eval $(generic-package)) diff --git a/patches/linux/6.12.1/0001-FIX-net-dsa-mv88e6xxx-Fix-timeout-on-waiting-for-PPU.patch b/patches/linux/6.12.1/0001-FIX-net-dsa-mv88e6xxx-Fix-timeout-on-waiting-for-PPU.patch new file mode 100644 index 00000000..326d24ca --- /dev/null +++ b/patches/linux/6.12.1/0001-FIX-net-dsa-mv88e6xxx-Fix-timeout-on-waiting-for-PPU.patch @@ -0,0 +1,32 @@ +From f5f25417c0e65f45c6a254e5a1f00c4fd5919058 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 12 Mar 2024 10:27:24 +0100 +Subject: [PATCH 01/24] [FIX] net: dsa: mv88e6xxx: Fix timeout on waiting for + PPU on 6393X +Organization: Addiva Elektronik + +In a multi-chip setup, delays of up to 750ms are observed before the +device (6393X) signals completion of PPU initialization (Global 1, +register 0, bit 15). Therefore, increase the timeout threshold to 1s. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 284270a4ade1..1f0b0c07ed9d 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -86,7 +86,7 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) + int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg, + u16 mask, u16 val) + { +- const unsigned long timeout = jiffies + msecs_to_jiffies(50); ++ const unsigned long timeout = jiffies + msecs_to_jiffies(1000); + u16 data; + int err; + int i; +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0002-net-dsa-mv88e6xxx-Improve-indirect-register-access-p.patch b/patches/linux/6.12.1/0002-net-dsa-mv88e6xxx-Improve-indirect-register-access-p.patch new file mode 100644 index 00000000..6bbb6c47 --- /dev/null +++ b/patches/linux/6.12.1/0002-net-dsa-mv88e6xxx-Improve-indirect-register-access-p.patch @@ -0,0 +1,216 @@ +From fc68336f274aac22426b271c4d4a7ef0bfc76006 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Wed, 27 Mar 2024 15:52:43 +0100 +Subject: [PATCH 02/24] net: dsa: mv88e6xxx: Improve indirect register access + perf on 6393 +Organization: Addiva Elektronik + +When operating in multi-chip mode, the 6393 family maps a subset of +commonly used global registers to the outermost address space (in +which only the SMI command and data registers were available in +previous families). + +Therefore, add a new set of SMI operations which remaps accesses to +such registers to the corresponding directly addressable register. All +other accesses use the regular indirect interface. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 7 +++ + drivers/net/dsa/mv88e6xxx/global1.h | 3 ++ + drivers/net/dsa/mv88e6xxx/global2.h | 3 ++ + drivers/net/dsa/mv88e6xxx/smi.c | 76 +++++++++++++++++++++++++++++ + drivers/net/dsa/mv88e6xxx/smi.h | 30 ++++++++++++ + 5 files changed, 119 insertions(+) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 1f0b0c07ed9d..f9d892d036be 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -6472,6 +6472,13 @@ static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) + /* Update the compatible info with the probed one */ + chip->info = info; + ++ /* Now that we know the exact chip in use, we might be able to ++ * make use of more efficient SMI operations ++ */ ++ err = mv88e6xxx_smi_init(chip, chip->bus, chip->sw_addr); ++ if (err) ++ return err; ++ + dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", + chip->info->prod_num, chip->info->name, rev); + +diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h +index 3dbb7a1b8fe1..5ea956aadecc 100644 +--- a/drivers/net/dsa/mv88e6xxx/global1.h ++++ b/drivers/net/dsa/mv88e6xxx/global1.h +@@ -218,6 +218,9 @@ + #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI 0x00e0 + #define MV88E6390_G1_MONITOR_MGMT_CTL_DATA_MASK 0x00ff + ++/* Offset 0x1B: Free Queue Size Register */ ++#define MV88E6XXX_G1_FREE_Q_SIZE 0x1b ++ + /* Offset 0x1C: Global Control 2 */ + #define MV88E6XXX_G1_CTL2 0x1c + #define MV88E6185_G1_CTL2_CASCADE_PORT_MASK 0xf000 +diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h +index 82f9b410de0b..3663645621c9 100644 +--- a/drivers/net/dsa/mv88e6xxx/global2.h ++++ b/drivers/net/dsa/mv88e6xxx/global2.h +@@ -143,6 +143,9 @@ + #define MV88E6XXX_G2_PRIO_OVERRIDE_QFPRIEN 0x0008 + #define MV88E6XXX_G2_PRIO_OVERRIDE_DATA_MASK 0x0007 + ++/* Offset 0x13: IMP Communication/Debug Register */ ++#define MV88E6390_G2_IMP_COMM 0x13 ++ + /* Offset 0x14: EEPROM Command */ + #define MV88E6XXX_G2_EEPROM_CMD 0x14 + #define MV88E6XXX_G2_EEPROM_CMD_BUSY 0x8000 +diff --git a/drivers/net/dsa/mv88e6xxx/smi.c b/drivers/net/dsa/mv88e6xxx/smi.c +index a990271b7482..f54bb0e79030 100644 +--- a/drivers/net/dsa/mv88e6xxx/smi.c ++++ b/drivers/net/dsa/mv88e6xxx/smi.c +@@ -8,6 +8,8 @@ + */ + + #include "chip.h" ++#include "global1.h" ++#include "global2.h" + #include "smi.h" + + /* The switch ADDR[4:1] configuration pins define the chip SMI device address +@@ -168,6 +170,78 @@ static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = { + .init = mv88e6xxx_smi_indirect_init, + }; + ++static u8 mv88e6393_smi_indirect_remap(int dev, int reg) ++{ ++ static const u8 g1_remap[32] = { ++ [MV88E6352_G1_VTU_FID] = MV88E6393_SMI_G1_VTU_FID, ++ [MV88E6352_G1_VTU_SID] = MV88E6393_SMI_G1_VTU_SID, ++ [MV88E6XXX_G1_STS] = MV88E6393_SMI_G1_STS, ++ [MV88E6XXX_G1_VTU_OP] = MV88E6393_SMI_G1_VTU_OP, ++ [MV88E6XXX_G1_VTU_VID] = MV88E6393_SMI_G1_VTU_VID, ++ [MV88E6XXX_G1_VTU_DATA1] = MV88E6393_SMI_G1_VTU_DATA1, ++ [MV88E6XXX_G1_VTU_DATA2] = MV88E6393_SMI_G1_VTU_DATA2, ++ [MV88E6352_G1_ATU_FID] = MV88E6393_SMI_G1_ATU_FID, ++ [MV88E6XXX_G1_ATU_CTL] = MV88E6393_SMI_G1_ATU_CTL, ++ [MV88E6XXX_G1_ATU_OP] = MV88E6393_SMI_G1_ATU_OP, ++ [MV88E6XXX_G1_ATU_DATA] = MV88E6393_SMI_G1_ATU_DATA, ++ [MV88E6XXX_G1_ATU_MAC01] = MV88E6393_SMI_G1_ATU_MAC01, ++ [MV88E6XXX_G1_ATU_MAC23] = MV88E6393_SMI_G1_ATU_MAC23, ++ [MV88E6XXX_G1_ATU_MAC45] = MV88E6393_SMI_G1_ATU_MAC45, ++ [MV88E6XXX_G1_FREE_Q_SIZE] = MV88E6393_SMI_G1_FREE_Q_SIZE, ++ [MV88E6XXX_G1_STATS_OP] = MV88E6393_SMI_G1_STATS_OP, ++ [MV88E6XXX_G1_STATS_COUNTER_32] = MV88E6393_SMI_G1_STATS_COUNTER_32, ++ [MV88E6XXX_G1_STATS_COUNTER_01] = MV88E6393_SMI_G1_STATS_COUNTER_01, ++ }; ++ ++ static const u8 g2_remap[32] = { ++ [MV88E6390_G2_IMP_COMM] = MV88E6393_SMI_G2_IMP_COMM, ++ [MV88E6352_G2_AVB_CMD] = MV88E6393_SMI_G2_AVB_CMD, ++ [MV88E6352_G2_AVB_DATA] = MV88E6393_SMI_G2_AVB_DATA, ++ [MV88E6XXX_G2_SMI_PHY_CMD] = MV88E6393_SMI_G2_SMI_PHY_CMD, ++ [MV88E6XXX_G2_SMI_PHY_DATA] = MV88E6393_SMI_G2_SMI_PHY_DATA, ++ [MV88E6393X_G2_MACLINK_INT_SRC] = MV88E6393_SMI_G2_MACLINK_INT_SRC, ++ }; ++ ++ switch (dev) { ++ case 0x1b: ++ return g1_remap[reg]; ++ case 0x1c: ++ return g2_remap[reg]; ++ } ++ ++ return 0; ++} ++ ++static int mv88e6393_smi_indirect_read(struct mv88e6xxx_chip *chip, ++ int dev, int reg, u16 *data) ++{ ++ u8 remap = mv88e6393_smi_indirect_remap(dev, reg); ++ ++ if (remap) ++ return mv88e6xxx_smi_direct_read(chip, chip->sw_addr, ++ remap, data); ++ ++ return mv88e6xxx_smi_indirect_read(chip, dev, reg, data); ++} ++ ++static int mv88e6393_smi_indirect_write(struct mv88e6xxx_chip *chip, ++ int dev, int reg, u16 data) ++{ ++ u8 remap = mv88e6393_smi_indirect_remap(dev, reg); ++ ++ if (remap) ++ return mv88e6xxx_smi_direct_write(chip, chip->sw_addr, ++ remap, data); ++ ++ return mv88e6xxx_smi_indirect_write(chip, dev, reg, data); ++} ++ ++static const struct mv88e6xxx_bus_ops mv88e6393_smi_indirect_ops = { ++ .read = mv88e6393_smi_indirect_read, ++ .write = mv88e6393_smi_indirect_write, ++ .init = mv88e6xxx_smi_indirect_init, ++}; ++ + int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip, + struct mii_bus *bus, int sw_addr) + { +@@ -175,6 +249,8 @@ int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip, + chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops; + else if (sw_addr == 0) + chip->smi_ops = &mv88e6xxx_smi_direct_ops; ++ else if (chip->info->family == MV88E6XXX_FAMILY_6393) ++ chip->smi_ops = &mv88e6393_smi_indirect_ops; + else if (chip->info->multi_chip) + chip->smi_ops = &mv88e6xxx_smi_indirect_ops; + else +diff --git a/drivers/net/dsa/mv88e6xxx/smi.h b/drivers/net/dsa/mv88e6xxx/smi.h +index c6c71d5757f5..788cf68b7b33 100644 +--- a/drivers/net/dsa/mv88e6xxx/smi.h ++++ b/drivers/net/dsa/mv88e6xxx/smi.h +@@ -31,6 +31,36 @@ + /* Offset 0x01: SMI Data Register */ + #define MV88E6XXX_SMI_DATA 0x01 + ++/* When using the 6393 in indirect addressing mode, a subset of the ++ * most commonly used registers are directly mapped out to the chip's ++ * top address space, allowing them to be directly accessed. ++ */ ++#define MV88E6393_SMI_G1_VTU_FID 0x02 ++#define MV88E6393_SMI_G1_VTU_SID 0x03 ++#define MV88E6393_SMI_G1_STS 0x04 ++#define MV88E6393_SMI_G1_VTU_OP 0x05 ++#define MV88E6393_SMI_G1_VTU_VID 0x06 ++#define MV88E6393_SMI_G1_VTU_DATA1 0x07 ++#define MV88E6393_SMI_G1_VTU_DATA2 0x08 ++#define MV88E6393_SMI_G1_ATU_FID 0x09 ++#define MV88E6393_SMI_G1_ATU_CTL 0x0a ++#define MV88E6393_SMI_G1_ATU_OP 0x0b ++#define MV88E6393_SMI_G1_ATU_DATA 0x0c ++#define MV88E6393_SMI_G1_ATU_MAC01 0x0d ++#define MV88E6393_SMI_G1_ATU_MAC23 0x0e ++#define MV88E6393_SMI_G1_ATU_MAC45 0x0f ++#define MV88E6393_SMI_G2_IMP_COMM 0x13 ++#define MV88E6393_SMI_G2_AVB_CMD 0x16 ++#define MV88E6393_SMI_G2_AVB_DATA 0x17 ++#define MV88E6393_SMI_G2_SMI_PHY_CMD 0x18 ++#define MV88E6393_SMI_G2_SMI_PHY_DATA 0x19 ++#define MV88E6393_SMI_G2_MACLINK_INT_SRC 0x1a ++#define MV88E6393_SMI_G1_FREE_Q_SIZE 0x1b ++#define MV88E6393_SMI_G1_STATS_OP 0x1d ++#define MV88E6393_SMI_G1_STATS_COUNTER_32 0x1e ++#define MV88E6393_SMI_G1_STATS_COUNTER_01 0x1f ++ ++ + int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip, + struct mii_bus *bus, int sw_addr); + +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0003-net-dsa-mv88e6xxx-Honor-ports-being-managed-via-in-b.patch b/patches/linux/6.12.1/0003-net-dsa-mv88e6xxx-Honor-ports-being-managed-via-in-b.patch new file mode 100644 index 00000000..60cff120 --- /dev/null +++ b/patches/linux/6.12.1/0003-net-dsa-mv88e6xxx-Honor-ports-being-managed-via-in-b.patch @@ -0,0 +1,48 @@ +From 66e1fc9ab54680989c02dab907743133674a07cf Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Mon, 22 Apr 2024 23:18:01 +0200 +Subject: [PATCH 03/24] net: dsa: mv88e6xxx: Honor ports being managed via + in-band-status +Organization: Addiva Elektronik + +Keep all link parameters in their unforced states when the port is +declared as being managed via in-band-status, and let the MAC +configure itself, via whatever method is being used (e.g. SGMII or +USXGMII autoneg) + +This state is the default set up by mv88e6xxx_port_setup_mac(), so all +we have to do is to make the phylink MAC callbacks no-ops in cases +when in-band-status is being used. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index f9d892d036be..98bd635b0ba9 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -964,6 +964,9 @@ static void mv88e6xxx_mac_link_down(struct phylink_config *config, + int port = dp->index; + int err = 0; + ++ if (mode == MLO_AN_INBAND) ++ return; ++ + ops = chip->info->ops; + + mv88e6xxx_reg_lock(chip); +@@ -996,6 +999,9 @@ static void mv88e6xxx_mac_link_up(struct phylink_config *config, + int port = dp->index; + int err = 0; + ++ if (mode == MLO_AN_INBAND) ++ return; ++ + ops = chip->info->ops; + + mv88e6xxx_reg_lock(chip); +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0004-net-dsa-mv88e6xxx-Limit-rsvd2cpu-policy-to-user-port.patch b/patches/linux/6.12.1/0004-net-dsa-mv88e6xxx-Limit-rsvd2cpu-policy-to-user-port.patch new file mode 100644 index 00000000..067813ac --- /dev/null +++ b/patches/linux/6.12.1/0004-net-dsa-mv88e6xxx-Limit-rsvd2cpu-policy-to-user-port.patch @@ -0,0 +1,103 @@ +From 7c9d33f9176e5d2173646aee7b15176e40fabbb0 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Wed, 24 Apr 2024 22:41:04 +0200 +Subject: [PATCH 04/24] net: dsa: mv88e6xxx: Limit rsvd2cpu policy to user + ports on 6393X +Organization: Addiva Elektronik + +For packets with a DA in the IEEE reserved L2 group range, originating +from a CPU, forward it as normal, rather than classifying it as +management. + +Example use-case: + + bridge (group_fwd_mask 0x4000) + / | \ + swp1 swp2 tap0 + \ / +(mv88e6xxx) + +We've created a bridge with a non-zero group_fwd_mask (allowing LLDP +in this example) containing a set of ports managed by mv88e6xxx and +some foreign interface (e.g. an L2 VPN tunnel). + +Since an LLDP packet coming in to the bridge from the other side of +tap0 is eligable for tx forward offloading, a FORWARD frame destined +for swp1 and swp2 would be send to the conduit interface. + +Before this change, due to rsvd2cpu being enabled on the CPU port, the +switch would try to trap it back to the CPU. Given that the CPU is +trusted, instead assume that it indeed meant for the packet to be +forwarded like any other. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/port.c | 31 +++++++++++++++++++++++++------ + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c +index 04053fdc6489..f25fb3214acb 100644 +--- a/drivers/net/dsa/mv88e6xxx/port.c ++++ b/drivers/net/dsa/mv88e6xxx/port.c +@@ -1432,6 +1432,23 @@ static int mv88e6393x_port_policy_write_all(struct mv88e6xxx_chip *chip, + return 0; + } + ++static int mv88e6393x_port_policy_write_user(struct mv88e6xxx_chip *chip, ++ u16 pointer, u8 data) ++{ ++ int err, port; ++ ++ for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { ++ if (!dsa_is_user_port(chip->ds, port)) ++ continue; ++ ++ err = mv88e6393x_port_policy_write(chip, port, pointer, data); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ + int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip, + enum mv88e6xxx_egress_direction direction, + int port) +@@ -1473,26 +1490,28 @@ int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip) + int err; + + /* Consider the frames with reserved multicast destination +- * addresses matching 01:80:c2:00:00:00 and +- * 01:80:c2:00:00:02 as MGMT. ++ * addresses matching 01:80:c2:00:00:00 and 01:80:c2:00:00:02 ++ * as MGMT when received on user ports. Forward as normal on ++ * CPU/DSA ports, to support bridges with non-zero ++ * group_fwd_masks. + */ + ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO; +- err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff); ++ err = mv88e6393x_port_policy_write_user(chip, ptr, 0xff); + if (err) + return err; + + ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI; +- err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff); ++ err = mv88e6393x_port_policy_write_user(chip, ptr, 0xff); + if (err) + return err; + + ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO; +- err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff); ++ err = mv88e6393x_port_policy_write_user(chip, ptr, 0xff); + if (err) + return err; + + ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI; +- err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff); ++ err = mv88e6393x_port_policy_write_user(chip, ptr, 0xff); + if (err) + return err; + +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0005-net-dsa-mv88e6xxx-Add-LED-infrastructure.patch b/patches/linux/6.12.1/0005-net-dsa-mv88e6xxx-Add-LED-infrastructure.patch new file mode 100644 index 00000000..307db072 --- /dev/null +++ b/patches/linux/6.12.1/0005-net-dsa-mv88e6xxx-Add-LED-infrastructure.patch @@ -0,0 +1,316 @@ +From 408a1681d4bbb44ede8d7d738f96a2fc27deb813 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Thu, 16 Nov 2023 19:44:32 +0100 +Subject: [PATCH 05/24] net: dsa: mv88e6xxx: Add LED infrastructure +Organization: Addiva Elektronik + +Parse DT for LEDs and register them for devices that support it, +though no actual implementations exist yet. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/Makefile | 1 + + drivers/net/dsa/mv88e6xxx/chip.c | 5 +- + drivers/net/dsa/mv88e6xxx/chip.h | 16 +++ + drivers/net/dsa/mv88e6xxx/leds.c | 185 +++++++++++++++++++++++++++++ + drivers/net/dsa/mv88e6xxx/leds.h | 12 ++ + 5 files changed, 218 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c + create mode 100644 drivers/net/dsa/mv88e6xxx/leds.h + +diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile +index a9a9651187db..6720d9303914 100644 +--- a/drivers/net/dsa/mv88e6xxx/Makefile ++++ b/drivers/net/dsa/mv88e6xxx/Makefile +@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o + mv88e6xxx-objs += global2_avb.o + mv88e6xxx-objs += global2_scratch.o + mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o ++mv88e6xxx-objs += leds.o + mv88e6xxx-objs += pcs-6185.o + mv88e6xxx-objs += pcs-6352.o + mv88e6xxx-objs += pcs-639x.o +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 98bd635b0ba9..97cebc490fac 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -37,6 +37,7 @@ + #include "global1.h" + #include "global2.h" + #include "hwtstamp.h" ++#include "leds.h" + #include "phy.h" + #include "port.h" + #include "ptp.h" +@@ -4115,7 +4116,9 @@ static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port) + return err; + } + +- return mv88e6xxx_setup_devlink_regions_port(ds, port); ++ err = err ? : mv88e6xxx_setup_devlink_regions_port(ds, port); ++ err = err ? : mv88e6xxx_port_setup_leds(ds, port); ++ return err; + } + + static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port) +diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h +index a54682240839..32c87ab754d1 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.h ++++ b/drivers/net/dsa/mv88e6xxx/chip.h +@@ -207,6 +207,7 @@ struct mv88e6xxx_avb_ops; + struct mv88e6xxx_ptp_ops; + struct mv88e6xxx_pcs_ops; + struct mv88e6xxx_cc_coeffs; ++struct mv88e6xxx_led_ops; + + struct mv88e6xxx_irq { + u16 masked; +@@ -330,6 +331,8 @@ struct mv88e6xxx_hw_stat { + int type; + }; + ++struct mv88e6xxx_led; ++ + struct mv88e6xxx_chip { + const struct mv88e6xxx_info *info; + +@@ -661,6 +664,9 @@ struct mv88e6xxx_ops { + /* Precision Time Protocol operations */ + const struct mv88e6xxx_ptp_ops *ptp_ops; + ++ /* LED operations */ ++ const struct mv88e6xxx_led_ops *led_ops; ++ + /* Phylink */ + void (*phylink_get_caps)(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config); +@@ -740,7 +746,17 @@ struct mv88e6xxx_pcs_ops { + void (*pcs_teardown)(struct mv88e6xxx_chip *chip, int port); + struct phylink_pcs *(*pcs_select)(struct mv88e6xxx_chip *chip, int port, + phy_interface_t mode); ++}; + ++struct mv88e6xxx_led_ops { ++ int (*brightness_set)(struct mv88e6xxx_led *led, ++ enum led_brightness brightness); ++ int (*blink_set)(struct mv88e6xxx_led *led, ++ unsigned long *delay_on, unsigned long *delay_off); ++ int (*hw_control_is_supported)(struct mv88e6xxx_led *led, ++ unsigned long flags); ++ int (*hw_control_set)(struct mv88e6xxx_led *led, unsigned long flags); ++ int (*hw_control_get)(struct mv88e6xxx_led *led, unsigned long *flags); + }; + + static inline bool mv88e6xxx_has_stu(struct mv88e6xxx_chip *chip) +diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c +new file mode 100644 +index 000000000000..e3de10991f29 +--- /dev/null ++++ b/drivers/net/dsa/mv88e6xxx/leds.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++#include ++ ++#include "chip.h" ++#include "leds.h" ++#include "port.h" ++ ++struct mv88e6xxx_led { ++ struct mv88e6xxx_chip *chip; ++ int port; ++ u8 index; ++ ++ struct led_classdev ldev; ++}; ++ ++static int mv88e6xxx_led_brightness_set(struct led_classdev *ldev, ++ enum led_brightness brightness) ++{ ++ const struct mv88e6xxx_led_ops *ops; ++ struct mv88e6xxx_led *led; ++ ++ led = container_of(ldev, struct mv88e6xxx_led, ldev); ++ ops = led->chip->info->ops->led_ops; ++ ++ if (!ops->brightness_set) ++ return -EOPNOTSUPP; ++ ++ return ops->brightness_set(led, brightness); ++} ++ ++static int mv88e6xxx_led_blink_set(struct led_classdev *ldev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ const struct mv88e6xxx_led_ops *ops; ++ struct mv88e6xxx_led *led; ++ ++ led = container_of(ldev, struct mv88e6xxx_led, ldev); ++ ops = led->chip->info->ops->led_ops; ++ ++ if (!ops->blink_set) ++ return -EOPNOTSUPP; ++ ++ return ops->blink_set(led, delay_on, delay_off); ++} ++ ++static int mv88e6xxx_led_hw_control_is_supported(struct led_classdev *ldev, ++ unsigned long flags) ++{ ++ const struct mv88e6xxx_led_ops *ops; ++ struct mv88e6xxx_led *led; ++ ++ led = container_of(ldev, struct mv88e6xxx_led, ldev); ++ ops = led->chip->info->ops->led_ops; ++ ++ if (!ops->hw_control_is_supported) ++ return -EOPNOTSUPP; ++ ++ return ops->hw_control_is_supported(led, flags); ++} ++ ++static int mv88e6xxx_led_hw_control_set(struct led_classdev *ldev, ++ unsigned long flags) ++{ ++ const struct mv88e6xxx_led_ops *ops; ++ struct mv88e6xxx_led *led; ++ ++ led = container_of(ldev, struct mv88e6xxx_led, ldev); ++ ops = led->chip->info->ops->led_ops; ++ ++ if (!ops->hw_control_set) ++ return -EOPNOTSUPP; ++ ++ return ops->hw_control_set(led, flags); ++} ++ ++static int mv88e6xxx_led_hw_control_get(struct led_classdev *ldev, ++ unsigned long *flags) ++{ ++ const struct mv88e6xxx_led_ops *ops; ++ struct mv88e6xxx_led *led; ++ ++ led = container_of(ldev, struct mv88e6xxx_led, ldev); ++ ops = led->chip->info->ops->led_ops; ++ ++ if (!ops->hw_control_get) ++ return -EOPNOTSUPP; ++ ++ return ops->hw_control_get(led, flags); ++} ++ ++static struct device *mv88e6xxx_led_hw_control_get_device(struct led_classdev *ldev) ++{ ++ struct mv88e6xxx_led *led; ++ struct dsa_port *dp; ++ ++ led = container_of(ldev, struct mv88e6xxx_led, ldev); ++ dp = dsa_to_port(led->chip->ds, led->port); ++ ++ if (dp && dp->user) ++ return &dp->user->dev; ++ ++ return NULL; ++} ++ ++static int mv88e6xxx_port_setup_led(struct mv88e6xxx_chip *chip, int port, ++ struct device_node *np) ++{ ++ struct led_init_data init_data = {}; ++ struct mv88e6xxx_led *led; ++ char *devname; ++ u32 index; ++ int err; ++ ++ err = of_property_read_u32(np, "reg", &index); ++ if (err) ++ return err; ++ ++ if (index >= 2) ++ return -EINVAL; ++ ++ led = devm_kzalloc(chip->dev, sizeof(*led), GFP_KERNEL); ++ if (!led) ++ return -ENOMEM; ++ ++ *led = (struct mv88e6xxx_led) { ++ .chip = chip, ++ .port = port, ++ .index = index, ++ ++ .ldev = { ++ .max_brightness = 1, ++ .brightness_set_blocking = mv88e6xxx_led_brightness_set, ++ .blink_set = mv88e6xxx_led_blink_set, ++ ++#ifdef CONFIG_LEDS_TRIGGERS ++ .hw_control_trigger = "netdev", ++ .hw_control_get_device = mv88e6xxx_led_hw_control_get_device, ++ ++ .hw_control_is_supported = mv88e6xxx_led_hw_control_is_supported, ++ .hw_control_set = mv88e6xxx_led_hw_control_set, ++ .hw_control_get = mv88e6xxx_led_hw_control_get, ++#endif ++ }, ++ }; ++ ++ devname = devm_kasprintf(chip->dev, GFP_KERNEL, "%s.%d", ++ dev_name(chip->dev), port); ++ if (!devname) ++ return -ENOMEM; ++ ++ init_data = (struct led_init_data) { ++ .fwnode = of_fwnode_handle(np), ++ .devname_mandatory = true, ++ .devicename = devname, ++ }; ++ ++ return devm_led_classdev_register_ext(chip->dev, &led->ldev, &init_data); ++} ++ ++int mv88e6xxx_port_setup_leds(struct dsa_switch *ds, int port) ++{ ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct mv88e6xxx_chip *chip = ds->priv; ++ struct device_node *pnp, *np; ++ int err; ++ ++ if (!chip->info->ops->led_ops) ++ return 0; ++ ++ if (!dp->dn) ++ return 0; ++ ++ pnp = of_get_child_by_name(dp->dn, "leds"); ++ if (!pnp) ++ return 0; ++ ++ for_each_available_child_of_node(pnp, np) { ++ err = mv88e6xxx_port_setup_led(chip, port, np); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} +diff --git a/drivers/net/dsa/mv88e6xxx/leds.h b/drivers/net/dsa/mv88e6xxx/leds.h +new file mode 100644 +index 000000000000..8afa2a0c0527 +--- /dev/null ++++ b/drivers/net/dsa/mv88e6xxx/leds.h +@@ -0,0 +1,12 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/* Marvell 88E6xxx Switch leds support. */ ++ ++#ifndef _MV88E6XXX_LEDS_H ++#define _MV88E6XXX_LEDS_H ++ ++#include "chip.h" ++ ++int mv88e6xxx_port_setup_leds(struct dsa_switch *ds, int port); ++ ++#endif /* _MV88E6XXX_LEDS_H */ +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0006-net-dsa-mv88e6xxx-Add-LED-support-for-6393X.patch b/patches/linux/6.12.1/0006-net-dsa-mv88e6xxx-Add-LED-support-for-6393X.patch new file mode 100644 index 00000000..63d6c460 --- /dev/null +++ b/patches/linux/6.12.1/0006-net-dsa-mv88e6xxx-Add-LED-support-for-6393X.patch @@ -0,0 +1,364 @@ +From 9bfe65e40336c449720f96230ccc22c831045e9d Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Thu, 16 Nov 2023 21:59:35 +0100 +Subject: [PATCH 06/24] net: dsa: mv88e6xxx: Add LED support for 6393X +Organization: Addiva Elektronik + +Trigger support: +- "none" +- "timer" +- "netdev" + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 1 + + drivers/net/dsa/mv88e6xxx/leds.c | 229 +++++++++++++++++++++++++++++++ + drivers/net/dsa/mv88e6xxx/leds.h | 2 + + drivers/net/dsa/mv88e6xxx/port.c | 33 +++++ + drivers/net/dsa/mv88e6xxx/port.h | 7 + + 5 files changed, 272 insertions(+) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 97cebc490fac..e8edf3970940 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -5627,6 +5627,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6390_avb_ops, + .ptp_ops = &mv88e6352_ptp_ops, ++ .led_ops = &mv88e6393x_led_ops, + .phylink_get_caps = mv88e6393x_phylink_get_caps, + .pcs_ops = &mv88e6393x_pcs_ops, + }; +diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c +index e3de10991f29..acdb5eca6647 100644 +--- a/drivers/net/dsa/mv88e6xxx/leds.c ++++ b/drivers/net/dsa/mv88e6xxx/leds.c +@@ -5,6 +5,13 @@ + #include "leds.h" + #include "port.h" + ++#define FLAG_ACT (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) ++#define FLAG_LINK BIT(TRIGGER_NETDEV_LINK) ++#define FLAG_LINK_10 BIT(TRIGGER_NETDEV_LINK_10) ++#define FLAG_LINK_100 BIT(TRIGGER_NETDEV_LINK_100) ++#define FLAG_LINK_1G BIT(TRIGGER_NETDEV_LINK_1000) ++#define FLAG_FULL BIT(TRIGGER_NETDEV_FULL_DUPLEX) ++ + struct mv88e6xxx_led { + struct mv88e6xxx_chip *chip; + int port; +@@ -13,6 +20,228 @@ struct mv88e6xxx_led { + struct led_classdev ldev; + }; + ++enum mv88e6393x_led_mode { ++ MV88E6393X_LED_MODE_BLINK = 0xd, ++ MV88E6393X_LED_MODE_OFF = 0xe, ++ MV88E6393X_LED_MODE_ON = 0xf, ++ ++ MV88E6393X_LED_MODES = 0x10 ++}; ++ ++static const unsigned long mv88e6393x_led_map_p1_p8[2][MV88E6393X_LED_MODES] = { ++ { ++ [0x1] = FLAG_ACT | FLAG_LINK_100 | FLAG_LINK_1G, ++ [0x2] = FLAG_ACT | FLAG_LINK_1G, ++ [0x3] = FLAG_ACT | FLAG_LINK, ++ [0x6] = FLAG_FULL, ++ [0x7] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_1G, ++ [0x8] = FLAG_LINK, ++ [0x9] = FLAG_LINK_10, ++ [0xa] = FLAG_ACT | FLAG_LINK_10, ++ [0xb] = FLAG_LINK_100 | FLAG_LINK_1G, ++ }, ++ { ++ [0x1] = FLAG_ACT, ++ [0x2] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_100, ++ [0x3] = FLAG_LINK_1G, ++ [0x5] = FLAG_ACT | FLAG_LINK, ++ [0x6] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_1G, ++ [0x7] = FLAG_LINK_10 | FLAG_LINK_1G, ++ [0x9] = FLAG_LINK_100, ++ [0xa] = FLAG_ACT | FLAG_LINK_100, ++ [0xb] = FLAG_LINK_10 | FLAG_LINK_100, ++ } ++}; ++ ++static const unsigned long mv88e6393x_led_map_p9_p10[2][MV88E6393X_LED_MODES] = { ++ { ++ [0x1] = FLAG_ACT | FLAG_LINK, ++ }, ++ { ++ [0x6] = FLAG_FULL, ++ [0x7] = FLAG_ACT | FLAG_LINK, ++ [0x8] = FLAG_LINK, ++ } ++}; ++ ++static const unsigned long *mv88e6393x_led_map(struct mv88e6xxx_led *led) ++{ ++ switch (led->port) { ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ case 8: ++ return mv88e6393x_led_map_p1_p8[led->index]; ++ case 9: ++ case 10: ++ return mv88e6393x_led_map_p9_p10[led->index]; ++ } ++ ++ return NULL; ++} ++ ++static int mv88e6393x_led_flags_to_mode(struct mv88e6xxx_led *led, unsigned long flags) ++{ ++ const unsigned long *map = mv88e6393x_led_map(led); ++ int i; ++ ++ if (!map) ++ return -ENODEV; ++ ++ if (!flags) ++ return MV88E6393X_LED_MODE_OFF; ++ ++ for (i = 0; i < MV88E6393X_LED_MODES; i++) { ++ if (map[i] == flags) ++ return i; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++static int mv88e6393x_led_mode_to_flags(struct mv88e6xxx_led *led, u8 mode, ++ unsigned long *flags) ++{ ++ const unsigned long *map = mv88e6393x_led_map(led); ++ ++ if (!map) ++ return -ENODEV; ++ ++ if (mode == MV88E6393X_LED_MODE_OFF) { ++ *flags = 0; ++ return 0; ++ } ++ ++ if (map[mode]) { ++ *flags = map[mode]; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int mv88e6393x_led_set(struct mv88e6xxx_led *led, int mode) ++{ ++ u16 ctrl; ++ int err; ++ ++ if (mode < 0) ++ return mode; ++ ++ mv88e6xxx_reg_lock(led->chip); ++ ++ err = mv88e6393x_port_led_read(led->chip, led->port, 0, &ctrl); ++ if (err) ++ goto out; ++ ++ switch (led->index) { ++ case 0: ++ ctrl &= ~0x0f; ++ ctrl |= mode; ++ break; ++ case 1: ++ ctrl &= ~0xf0; ++ ctrl |= mode << 4; ++ } ++ ++ err = mv88e6393x_port_led_write(led->chip, led->port, 0, ctrl); ++out: ++ mv88e6xxx_reg_unlock(led->chip); ++ return err; ++} ++ ++static int mv88e6393x_led_get(struct mv88e6xxx_led *led) ++{ ++ u16 ctrl; ++ int err; ++ ++ mv88e6xxx_reg_lock(led->chip); ++ err = mv88e6393x_port_led_read(led->chip, led->port, 0, &ctrl); ++ mv88e6xxx_reg_unlock(led->chip); ++ if (err) ++ return err; ++ ++ switch (led->index) { ++ case 0: ++ return ctrl & 0xf; ++ case 1: ++ return (ctrl >> 4) & 0xf; ++ } ++ ++ return -EINVAL; ++} ++ ++static int mv88e6393x_led_brightness_set(struct mv88e6xxx_led *led, ++ enum led_brightness brightness) ++{ ++ if (brightness == LED_OFF) ++ return mv88e6393x_led_set(led, MV88E6393X_LED_MODE_OFF); ++ ++ return mv88e6393x_led_set(led, MV88E6393X_LED_MODE_ON); ++} ++static int mv88e6393x_led_blink_set(struct mv88e6xxx_led *led, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ int err; ++ ++ /* Defer anything other than 50% duty cycles to software */ ++ if (*delay_on != *delay_off) ++ return -EINVAL; ++ ++ /* Reject values outside ~20% of our default rate (84ms) */ ++ if (*delay_on && ((*delay_on < 30) || (*delay_on > 50))) ++ return -EINVAL; ++ ++ err = mv88e6393x_led_set(led, MV88E6393X_LED_MODE_BLINK); ++ if (!err) ++ *delay_on = *delay_off = 42; ++ ++ return err; ++} ++ ++static int mv88e6393x_led_hw_control_is_supported(struct mv88e6xxx_led *led, ++ unsigned long flags) ++{ ++ int mode = mv88e6393x_led_flags_to_mode(led, flags); ++ ++ return (mode < 0) ? mode : 0; ++} ++ ++static int mv88e6393x_led_hw_control_set(struct mv88e6xxx_led *led, ++ unsigned long flags) ++{ ++ int mode = mv88e6393x_led_flags_to_mode(led, flags); ++ ++ if (mode < 0) ++ return mode; ++ ++ return mv88e6393x_led_set(led, mode); ++} ++ ++static int mv88e6393x_led_hw_control_get(struct mv88e6xxx_led *led, ++ unsigned long *flags) ++{ ++ int mode = mv88e6393x_led_get(led); ++ ++ if (mode < 0) ++ return mode; ++ ++ return mv88e6393x_led_mode_to_flags(led, mode, flags); ++} ++ ++const struct mv88e6xxx_led_ops mv88e6393x_led_ops = { ++ .brightness_set = mv88e6393x_led_brightness_set, ++ .blink_set = mv88e6393x_led_blink_set, ++ .hw_control_is_supported = mv88e6393x_led_hw_control_is_supported, ++ .hw_control_set = mv88e6393x_led_hw_control_set, ++ .hw_control_get = mv88e6393x_led_hw_control_get, ++}; ++ + static int mv88e6xxx_led_brightness_set(struct led_classdev *ldev, + enum led_brightness brightness) + { +diff --git a/drivers/net/dsa/mv88e6xxx/leds.h b/drivers/net/dsa/mv88e6xxx/leds.h +index 8afa2a0c0527..542345d23dc5 100644 +--- a/drivers/net/dsa/mv88e6xxx/leds.h ++++ b/drivers/net/dsa/mv88e6xxx/leds.h +@@ -7,6 +7,8 @@ + + #include "chip.h" + ++extern const struct mv88e6xxx_led_ops mv88e6393x_led_ops; ++ + int mv88e6xxx_port_setup_leds(struct dsa_switch *ds, int port); + + #endif /* _MV88E6XXX_LEDS_H */ +diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c +index f25fb3214acb..aa5d312d8aa5 100644 +--- a/drivers/net/dsa/mv88e6xxx/port.c ++++ b/drivers/net/dsa/mv88e6xxx/port.c +@@ -1558,6 +1558,39 @@ int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype); + } + ++/* Offset 0x16: LED Control Register */ ++ ++int mv88e6393x_port_led_write(struct mv88e6xxx_chip *chip, int port, ++ unsigned int pointer, u16 data) ++{ ++ u16 cmd = BIT(15) | ((pointer & 0x7) << 12) | (data & 0x7ff); ++ int err; ++ ++ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_LED_CONTROL, cmd); ++ if (err) ++ return err; ++ ++ return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_LED_CONTROL, 15, 0); ++} ++ ++int mv88e6393x_port_led_read(struct mv88e6xxx_chip *chip, int port, ++ unsigned int pointer, u16 *data) ++{ ++ u16 cmd = (pointer & 0x7) << 12; ++ int err; ++ ++ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_LED_CONTROL, cmd); ++ if (err) ++ return err; ++ ++ err = mv88e6xxx_port_read(chip, port, MV88E6393X_PORT_LED_CONTROL, &cmd); ++ if (err) ++ return err; ++ ++ *data = cmd & 0x7ff; ++ return 0; ++} ++ + /* Offset 0x18: Port IEEE Priority Remapping Registers [0-3] + * Offset 0x19: Port IEEE Priority Remapping Registers [4-7] + */ +diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h +index ddadeb9bfdae..7157864dc20f 100644 +--- a/drivers/net/dsa/mv88e6xxx/port.h ++++ b/drivers/net/dsa/mv88e6xxx/port.h +@@ -309,6 +309,9 @@ + /* Offset 0x13: OutFiltered Counter */ + #define MV88E6XXX_PORT_OUT_FILTERED 0x13 + ++/* Offset 0x16: LED Control Register */ ++#define MV88E6393X_PORT_LED_CONTROL 0x16 ++ + /* Offset 0x18: IEEE Priority Mapping Table */ + #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18 + #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000 +@@ -425,6 +428,10 @@ int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port, + enum mv88e6xxx_policy_action action); + int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, + u16 etype); ++int mv88e6393x_port_led_write(struct mv88e6xxx_chip *chip, int port, ++ unsigned int pointer, u16 data); ++int mv88e6393x_port_led_read(struct mv88e6xxx_chip *chip, int port, ++ unsigned int pointer, u16 *data); + int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip, + enum mv88e6xxx_egress_direction direction, + int port); +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0007-net-dsa-tag_dsa-Use-tag-priority-as-initial-skb-prio.patch b/patches/linux/6.12.1/0007-net-dsa-tag_dsa-Use-tag-priority-as-initial-skb-prio.patch new file mode 100644 index 00000000..00cce3f1 --- /dev/null +++ b/patches/linux/6.12.1/0007-net-dsa-tag_dsa-Use-tag-priority-as-initial-skb-prio.patch @@ -0,0 +1,48 @@ +From 0f009562d467672b7f5ff9366ad4ec9df9044137 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 28 May 2024 10:38:42 +0200 +Subject: [PATCH 07/24] net: dsa: tag_dsa: Use tag priority as initial + skb->priority +Organization: Addiva Elektronik + +Use the 3-bit priority field from the DSA tag as the initial packet +priority on ingress to the CPU. + +These bits contain the frame priority (FPri) of the packet. Barring +any non-standard policy configuration, this corresponds to: + +1. The original PCP bits if the packet is received with a VLAN tag +2. ...or the the 3 MSBs of the DSCP field, if it is an IP packet +3. ...otherwise 0 + +Ideally we could then map this priority to an internal one, like we +can do with an "ingress-qos-map" on VLAN interfaces. Until that is +implemented, support the setup that is likely to be the most common; a +1:1 mapping from FPri to skb->priority. + +Signed-off-by: Tobias Waldekranz +--- + net/dsa/tag_dsa.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c +index 2a2c4fb61a65..a00ae6bf2971 100644 +--- a/net/dsa/tag_dsa.c ++++ b/net/dsa/tag_dsa.c +@@ -323,6 +323,13 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev, + dsa_strip_etype_header(skb, DSA_HLEN + extra); + } + ++ /* Ideally we would have a way of configuring the mapping of PCP ++ * bits to skb->priority on DSA ports (like ingress-qos-map for ++ * vlan interfaces). For now, assume that a 1:1 mapping is more ++ * useful than ignoring the priority altogether. ++ */ ++ skb->priority = dsa_header[2] >> 5; ++ + return skb; + } + +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0008-net-dsa-Support-MDB-memberships-whose-L2-addresses-o.patch b/patches/linux/6.12.1/0008-net-dsa-Support-MDB-memberships-whose-L2-addresses-o.patch new file mode 100644 index 00000000..ac3690be --- /dev/null +++ b/patches/linux/6.12.1/0008-net-dsa-Support-MDB-memberships-whose-L2-addresses-o.patch @@ -0,0 +1,74 @@ +From 027a5fcd4da6cf02ff8d2f6dc5ff1202f81db8ca Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 16 Jan 2024 16:00:55 +0100 +Subject: [PATCH 08/24] net: dsa: Support MDB memberships whose L2 addresses + overlap +Organization: Addiva Elektronik + +Multiple IP multicast groups (32 for v4, 2^80 for v6) map to the same +L2 address. This means that switchdev drivers may receive multiple MDB +additions for a particular L2 group on the same port. Since these were +not reference counted before this change, removing a group membership +after two overlapping memberships had been added would result in the +membership being removed from hardware, even though one reference to +the address still remained. + +Steps to reproduce: + + root@infix:~# mvls atu | grep 01:02:03 + root@infix:~# bridge mdb add dev br0 port e8 grp 238.1.2.3 permanent + root@infix:~# bridge mdb add dev br0 port e8 grp 239.1.2.3 permanent + root@infix:~# mvls atu | grep 01:02:03 + 01:00:5e:01:02:03 1 static - - . . . . . . . . 8 . . + root@infix:~# bridge mdb del dev br0 port e8 grp 239.1.2.3 + root@infix:~# mvls atu | grep 01:02:03 + root@infix:~# + +Therefore, reference count MDB memberships and keep them in hardware +as long as the count is positive. Fortunately, all the infrastructure +needed to do this is already in place, since it is also needed on CPU +and DSA ports. Thus, "implement" this by simply removing the guards +which previously skipped reference countung on user ports. + +Signed-off-by: Tobias Waldekranz +--- + net/dsa/switch.c | 16 ---------------- + 1 file changed, 16 deletions(-) + +diff --git a/net/dsa/switch.c b/net/dsa/switch.c +index 3d2feeea897b..628e8a884dde 100644 +--- a/net/dsa/switch.c ++++ b/net/dsa/switch.c +@@ -164,14 +164,6 @@ static int dsa_port_do_mdb_add(struct dsa_port *dp, + int port = dp->index; + int err = 0; + +- /* No need to bother with refcounting for user ports */ +- if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp))) { +- err = ds->ops->port_mdb_add(ds, port, mdb, db); +- trace_dsa_mdb_add_hw(dp, mdb->addr, mdb->vid, &db, err); +- +- return err; +- } +- + mutex_lock(&dp->addr_lists_lock); + + a = dsa_mac_addr_find(&dp->mdbs, mdb->addr, mdb->vid, db); +@@ -216,14 +208,6 @@ static int dsa_port_do_mdb_del(struct dsa_port *dp, + int port = dp->index; + int err = 0; + +- /* No need to bother with refcounting for user ports */ +- if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp))) { +- err = ds->ops->port_mdb_del(ds, port, mdb, db); +- trace_dsa_mdb_del_hw(dp, mdb->addr, mdb->vid, &db, err); +- +- return err; +- } +- + mutex_lock(&dp->addr_lists_lock); + + a = dsa_mac_addr_find(&dp->mdbs, mdb->addr, mdb->vid, db); +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0009-net-dsa-Support-EtherType-based-priority-overrides.patch b/patches/linux/6.12.1/0009-net-dsa-Support-EtherType-based-priority-overrides.patch new file mode 100644 index 00000000..d1b20d18 --- /dev/null +++ b/patches/linux/6.12.1/0009-net-dsa-Support-EtherType-based-priority-overrides.patch @@ -0,0 +1,118 @@ +From ef232a32e69a5edb1a62067d4871fb70e8c3ddd7 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Thu, 21 Mar 2024 19:12:15 +0100 +Subject: [PATCH 09/24] net: dsa: Support EtherType based priority overrides +Organization: Addiva Elektronik + +Signed-off-by: Tobias Waldekranz +--- + include/net/dsa.h | 4 ++++ + net/dsa/user.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 58 insertions(+), 2 deletions(-) + +diff --git a/include/net/dsa.h b/include/net/dsa.h +index d7a6c2930277..db30c059b3c2 100644 +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -968,6 +968,10 @@ struct dsa_switch_ops { + const u8 *sel, int nsel); + int (*port_get_apptrust)(struct dsa_switch *ds, int port, u8 *sel, + int *nsel); ++ int (*port_add_etype_prio)(struct dsa_switch *ds, int port, u16 etype, ++ u8 prio); ++ int (*port_del_etype_prio)(struct dsa_switch *ds, int port, u16 etype, ++ u8 prio); + + /* + * Suspend and resume +diff --git a/net/dsa/user.c b/net/dsa/user.c +index 64f660d2334b..e13fb22e2c2b 100644 +--- a/net/dsa/user.c ++++ b/net/dsa/user.c +@@ -2294,6 +2294,34 @@ dsa_user_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app) + return 0; + } + ++static int __maybe_unused ++dsa_user_dcbnl_set_etype_prio(struct net_device *dev, struct dcb_app *app) ++{ ++ struct dsa_port *dp = dsa_user_to_port(dev); ++ struct dsa_switch *ds = dp->ds; ++ unsigned long mask, new_prio; ++ int err; ++ ++ if (!ds->ops->port_add_etype_prio) ++ return -EOPNOTSUPP; ++ ++ err = dcb_ieee_setapp(dev, app); ++ if (err) ++ return err; ++ ++ mask = dcb_ieee_getapp_mask(dev, app); ++ new_prio = __fls(mask); ++ ++ err = ds->ops->port_add_etype_prio(ds, dp->index, ++ app->protocol, new_prio); ++ if (err) { ++ dcb_ieee_delapp(dev, app); ++ return err; ++ } ++ ++ return 0; ++} ++ + static int __maybe_unused dsa_user_dcbnl_ieee_setapp(struct net_device *dev, + struct dcb_app *app) + { +@@ -2303,7 +2331,7 @@ static int __maybe_unused dsa_user_dcbnl_ieee_setapp(struct net_device *dev, + case 0: + return dsa_user_dcbnl_set_default_prio(dev, app); + default: +- return -EOPNOTSUPP; ++ return dsa_user_dcbnl_set_etype_prio(dev, app); + } + break; + case IEEE_8021QAZ_APP_SEL_DSCP: +@@ -2376,6 +2404,30 @@ dsa_user_dcbnl_del_dscp_prio(struct net_device *dev, struct dcb_app *app) + return 0; + } + ++static int __maybe_unused ++dsa_user_dcbnl_del_etype_prio(struct net_device *dev, struct dcb_app *app) ++{ ++ struct dsa_port *dp = dsa_user_to_port(dev); ++ struct dsa_switch *ds = dp->ds; ++ int err; ++ ++ if (!ds->ops->port_del_etype_prio) ++ return -EOPNOTSUPP; ++ ++ err = dcb_ieee_delapp(dev, app); ++ if (err) ++ return err; ++ ++ err = ds->ops->port_del_etype_prio(ds, dp->index, ++ app->protocol, app->priority); ++ if (err) { ++ dcb_ieee_setapp(dev, app); ++ return err; ++ } ++ ++ return 0; ++} ++ + static int __maybe_unused dsa_user_dcbnl_ieee_delapp(struct net_device *dev, + struct dcb_app *app) + { +@@ -2385,7 +2437,7 @@ static int __maybe_unused dsa_user_dcbnl_ieee_delapp(struct net_device *dev, + case 0: + return dsa_user_dcbnl_del_default_prio(dev, app); + default: +- return -EOPNOTSUPP; ++ return dsa_user_dcbnl_del_etype_prio(dev, app); + } + break; + case IEEE_8021QAZ_APP_SEL_DSCP: +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0010-net-dsa-mv88e6xxx-Support-EtherType-based-priority-o.patch b/patches/linux/6.12.1/0010-net-dsa-mv88e6xxx-Support-EtherType-based-priority-o.patch new file mode 100644 index 00000000..be0ee635 --- /dev/null +++ b/patches/linux/6.12.1/0010-net-dsa-mv88e6xxx-Support-EtherType-based-priority-o.patch @@ -0,0 +1,376 @@ +From 48338a7ca5f0a7be3b16acd1762ec0b73088ac4c Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Fri, 22 Mar 2024 16:15:43 +0100 +Subject: [PATCH 10/24] net: dsa: mv88e6xxx: Support EtherType based priority + overrides +Organization: Addiva Elektronik + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 64 +++++++++++++++++++++++++++++ + drivers/net/dsa/mv88e6xxx/chip.h | 21 ++++++++++ + drivers/net/dsa/mv88e6xxx/global2.c | 56 ++++++++++++++++++++++++- + drivers/net/dsa/mv88e6xxx/global2.h | 4 ++ + drivers/net/dsa/mv88e6xxx/port.c | 46 +++++++++++++++++++++ + drivers/net/dsa/mv88e6xxx/port.h | 20 +++++++-- + 6 files changed, 207 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index e8edf3970940..3151df2a27c7 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -1715,6 +1715,11 @@ static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) + + static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) + { ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(chip->qpri_po); i++) ++ refcount_set(&chip->qpri_po[i].refcnt, 0); ++ + if (chip->info->ops->pot_clear) + return chip->info->ops->pot_clear(chip); + +@@ -3386,6 +3391,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + + chip->ports[port].chip = chip; + chip->ports[port].port = port; ++ refcount_set(&chip->ports[port].etype.refcnt, 0); + + err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, + SPEED_UNFORCED, DUPLEX_UNFORCED, +@@ -6532,6 +6538,7 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) + chip->dev = dev; + + mutex_init(&chip->reg_lock); ++ mutex_init(&chip->arb_lock); + INIT_LIST_HEAD(&chip->mdios); + idr_init(&chip->policies); + INIT_LIST_HEAD(&chip->msts); +@@ -7064,6 +7071,61 @@ static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index, + return err_sync ? : err_pvt; + } + ++static int mv88e6xxx_port_add_etype_prio(struct dsa_switch *ds, int port, ++ u16 etype, u8 prio) ++{ ++ struct mv88e6xxx_chip *chip = ds->priv; ++ int err; ++ ++ mv88e6xxx_reg_lock(chip); ++ err = mv88e6xxx_port_claim_ether_type(chip, port, etype); ++ if (err) ++ goto err; ++ ++ err = mv88e6xxx_g2_claim_qpri_po(chip, ++ MV88E6XXX_G2_PRIO_OVERRIDE_PTR_ETYPE, ++ prio); ++ if (err) ++ goto err_relinquish_etype; ++ ++ mv88e6xxx_reg_unlock(chip); ++ return 0; ++ ++err_relinquish_etype: ++ mv88e6xxx_port_relinquish_ether_type(chip, port); ++err: ++ mv88e6xxx_reg_unlock(chip); ++ return err; ++} ++ ++static int mv88e6xxx_port_del_etype_prio(struct dsa_switch *ds, int port, ++ u16 etype, u8 prio) ++{ ++ struct mv88e6xxx_chip *chip = ds->priv; ++ int err; ++ ++ mv88e6xxx_reg_lock(chip); ++ err = mv88e6xxx_g2_relinquish_qpri_po(chip, ++ MV88E6XXX_G2_PRIO_OVERRIDE_PTR_ETYPE); ++ if (err) ++ goto err; ++ ++ err = mv88e6xxx_port_relinquish_ether_type(chip, port); ++ if (err) ++ goto err_claim_po; ++ ++ mv88e6xxx_reg_unlock(chip); ++ return 0; ++ ++err_claim_po: ++ mv88e6xxx_g2_claim_qpri_po(chip, ++ MV88E6XXX_G2_PRIO_OVERRIDE_PTR_ETYPE, ++ prio); ++err: ++ mv88e6xxx_reg_unlock(chip); ++ return err; ++} ++ + static const struct phylink_mac_ops mv88e6xxx_phylink_mac_ops = { + .mac_select_pcs = mv88e6xxx_mac_select_pcs, + .mac_prepare = mv88e6xxx_mac_prepare, +@@ -7133,6 +7195,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { + .crosschip_lag_change = mv88e6xxx_crosschip_lag_change, + .crosschip_lag_join = mv88e6xxx_crosschip_lag_join, + .crosschip_lag_leave = mv88e6xxx_crosschip_lag_leave, ++ .port_add_etype_prio = mv88e6xxx_port_add_etype_prio, ++ .port_del_etype_prio = mv88e6xxx_port_del_etype_prio, + }; + + static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) +diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h +index 32c87ab754d1..25edc2534979 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.h ++++ b/drivers/net/dsa/mv88e6xxx/chip.h +@@ -293,6 +293,11 @@ struct mv88e6xxx_port { + + /* MacAuth Bypass control flag */ + bool mab; ++ ++ struct { ++ refcount_t refcnt; ++ u16 proto; ++ } etype; + }; + + enum mv88e6xxx_region_id { +@@ -331,6 +336,11 @@ struct mv88e6xxx_hw_stat { + int type; + }; + ++struct mv88e6xxx_po { ++ refcount_t refcnt; ++ u8 pri; ++}; ++ + struct mv88e6xxx_led; + + struct mv88e6xxx_chip { +@@ -348,6 +358,14 @@ struct mv88e6xxx_chip { + /* This mutex protects the access to the switch registers */ + struct mutex reg_lock; + ++ /* This mutex protects arbitration of hardware resources which ++ * may be allocated by multiple kernel consumers. As an ++ * example, the dcb(8) facility manages priority overrides ++ * independently per interface, whereas the hardware only ++ * supports a single priority per chip. ++ */ ++ struct mutex arb_lock; ++ + /* The MII bus and the address on the bus that is used to + * communication with the switch + */ +@@ -437,6 +455,9 @@ struct mv88e6xxx_chip { + + /* Bridge MST to SID mappings */ + struct list_head msts; ++ ++ /* Queue priority overrides */ ++ struct mv88e6xxx_po qpri_po[16]; + }; + + struct mv88e6xxx_bus_ops { +diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c +index b2b5f6ba438f..2c52903e8992 100644 +--- a/drivers/net/dsa/mv88e6xxx/global2.c ++++ b/drivers/net/dsa/mv88e6xxx/global2.c +@@ -315,7 +315,7 @@ int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats) + static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer, + u8 data) + { +- u16 val = (pointer << 8) | (data & 0x7); ++ u16 val = (pointer << 8) | (data & 0xf); + + return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PRIO_OVERRIDE, + MV88E6XXX_G2_PRIO_OVERRIDE_UPDATE | val); +@@ -335,6 +335,60 @@ int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip) + return err; + } + ++int mv88e6xxx_g2_claim_qpri_po(struct mv88e6xxx_chip *chip, u8 pointer, ++ u8 qpri) ++{ ++ struct mv88e6xxx_po *po; ++ int err = 0; ++ ++ if (pointer > ARRAY_SIZE(chip->qpri_po)) ++ return -EINVAL; ++ ++ if (qpri > 7) ++ return -ERANGE; ++ ++ po = &chip->qpri_po[pointer]; ++ ++ mutex_lock(&chip->arb_lock); ++ if (refcount_read(&po->refcnt)) { ++ if (qpri == po->pri) ++ refcount_inc(&po->refcnt); ++ else ++ err = -EBUSY; ++ } else { ++ err = mv88e6xxx_g2_pot_write(chip, pointer, ++ MV88E6XXX_G2_PRIO_OVERRIDE_QFPRIEN | qpri); ++ if (!err) { ++ refcount_set(&po->refcnt, 1); ++ po->pri = qpri; ++ } ++ } ++ mutex_unlock(&chip->arb_lock); ++ ++ return err; ++} ++ ++int mv88e6xxx_g2_relinquish_qpri_po(struct mv88e6xxx_chip *chip, u8 pointer) ++{ ++ struct mv88e6xxx_po *po; ++ int err = 0; ++ ++ if (pointer > ARRAY_SIZE(chip->qpri_po)) ++ return -EINVAL; ++ ++ po = &chip->qpri_po[pointer]; ++ ++ mutex_lock(&chip->arb_lock); ++ if (refcount_dec_and_test(&po->refcnt)) { ++ err = mv88e6xxx_g2_pot_write(chip, pointer, 0); ++ if (err) ++ refcount_set(&po->refcnt, 1); ++ } ++ mutex_unlock(&chip->arb_lock); ++ ++ return err; ++} ++ + /* Offset 0x14: EEPROM Command + * Offset 0x15: EEPROM Data (for 16-bit data access) + * Offset 0x15: EEPROM Addr (for 8-bit data access) +diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h +index 3663645621c9..496269c26c50 100644 +--- a/drivers/net/dsa/mv88e6xxx/global2.h ++++ b/drivers/net/dsa/mv88e6xxx/global2.h +@@ -138,6 +138,7 @@ + #define MV88E6XXX_G2_PRIO_OVERRIDE_UPDATE 0x8000 + #define MV88E6XXX_G2_PRIO_OVERRIDE_FPRISET 0x1000 + #define MV88E6XXX_G2_PRIO_OVERRIDE_PTR_MASK 0x0f00 ++#define MV88E6XXX_G2_PRIO_OVERRIDE_PTR_ETYPE 0xc + #define MV88E6352_G2_PRIO_OVERRIDE_QPRIAVBEN 0x0080 + #define MV88E6352_G2_PRIO_OVERRIDE_DATAAVB_MASK 0x0030 + #define MV88E6XXX_G2_PRIO_OVERRIDE_QFPRIEN 0x0008 +@@ -359,6 +360,9 @@ int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip); + int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip); + + int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip); ++int mv88e6xxx_g2_claim_qpri_po(struct mv88e6xxx_chip *chip, u8 pointer, ++ u8 qpri); ++int mv88e6xxx_g2_relinquish_qpri_po(struct mv88e6xxx_chip *chip, u8 pointer); + + int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num, + bool hash, u16 mask); +diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c +index aa5d312d8aa5..84900814c456 100644 +--- a/drivers/net/dsa/mv88e6xxx/port.c ++++ b/drivers/net/dsa/mv88e6xxx/port.c +@@ -1558,6 +1558,52 @@ int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype); + } + ++int mv88e6xxx_port_claim_ether_type(struct mv88e6xxx_chip *chip, int port, ++ u16 etype) ++{ ++ struct mv88e6xxx_port *p = &chip->ports[port]; ++ int err = 0; ++ ++ if (!chip->info->ops->port_set_ether_type) ++ return -EOPNOTSUPP; ++ ++ mutex_lock(&chip->arb_lock); ++ if (refcount_read(&p->etype.refcnt)) { ++ if (etype == p->etype.proto) ++ refcount_inc(&p->etype.refcnt); ++ else ++ err = -EBUSY; ++ } else { ++ err = chip->info->ops->port_set_ether_type(chip, port, etype); ++ if (!err) { ++ refcount_set(&p->etype.refcnt, 1); ++ p->etype.proto = etype; ++ } ++ } ++ mutex_unlock(&chip->arb_lock); ++ ++ return err; ++} ++ ++int mv88e6xxx_port_relinquish_ether_type(struct mv88e6xxx_chip *chip, int port) ++{ ++ struct mv88e6xxx_port *p = &chip->ports[port]; ++ int err = 0; ++ ++ if (!chip->info->ops->port_set_ether_type) ++ return -EOPNOTSUPP; ++ ++ mutex_lock(&chip->arb_lock); ++ if (refcount_dec_and_test(&p->etype.refcnt)) { ++ err = chip->info->ops->port_set_ether_type(chip, port, ++ MV88E6XXX_PORT_ETH_TYPE_DEFAULT); ++ if (err) ++ refcount_set(&p->etype.refcnt, 1); ++ } ++ mutex_unlock(&chip->arb_lock); ++ return err; ++} ++ + /* Offset 0x16: LED Control Register */ + + int mv88e6393x_port_led_write(struct mv88e6xxx_chip *chip, int port, +diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h +index 7157864dc20f..7edb04c41ac8 100644 +--- a/drivers/net/dsa/mv88e6xxx/port.h ++++ b/drivers/net/dsa/mv88e6xxx/port.h +@@ -286,7 +286,18 @@ + + /* Offset 0x0F: Port Special Ether Type */ + #define MV88E6XXX_PORT_ETH_TYPE 0x0f +-#define MV88E6XXX_PORT_ETH_TYPE_DEFAULT 0x9100 ++ ++/* When MV88E6XXX_PORT_ETH_TYPE is used to override the queue priority ++ * of matching packets, the override applies to all the chip's ++ * ports. However, if the packet also matches a traffic class that the ++ * hardware classifies as being of higher priority, then that class's ++ * override configuration is used instead, even if that override is ++ * disabled. The class which is one level higher than EType is PPPoE, ++ * so by using that as the default value when no other value has been ++ * requested, we effectively disable the EType class for that port. ++ */ ++#define MV88E6XXX_PORT_ETH_TYPE_DEFAULT ETH_P_PPP_DISC ++ + + /* Offset 0x10: InDiscards Low Counter */ + #define MV88E6XXX_PORT_IN_DISCARD_LO 0x10 +@@ -426,8 +437,13 @@ int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port, + int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port, + enum mv88e6xxx_policy_mapping mapping, + enum mv88e6xxx_policy_action action); ++int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, ++ u16 etype); + int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, + u16 etype); ++int mv88e6xxx_port_claim_ether_type(struct mv88e6xxx_chip *chip, int port, ++ u16 etype); ++int mv88e6xxx_port_relinquish_ether_type(struct mv88e6xxx_chip *chip, int port); + int mv88e6393x_port_led_write(struct mv88e6xxx_chip *chip, int port, + unsigned int pointer, u16 data); + int mv88e6393x_port_led_read(struct mv88e6xxx_chip *chip, int port, +@@ -438,8 +454,6 @@ int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip, + int mv88e6393x_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, + int upstream_port); + int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip); +-int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, +- u16 etype); + int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, + bool message_port); + int mv88e6xxx_port_set_trunk(struct mv88e6xxx_chip *chip, int port, +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0011-net-dsa-mv88e6xxx-Add-mqprio-qdisc-support.patch b/patches/linux/6.12.1/0011-net-dsa-mv88e6xxx-Add-mqprio-qdisc-support.patch new file mode 100644 index 00000000..30c23eb2 --- /dev/null +++ b/patches/linux/6.12.1/0011-net-dsa-mv88e6xxx-Add-mqprio-qdisc-support.patch @@ -0,0 +1,162 @@ +From 2c3ceab75d2ebb36326a5bc09b17d9409a11d2fa Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 28 May 2024 11:04:22 +0200 +Subject: [PATCH 11/24] net: dsa: mv88e6xxx: Add mqprio qdisc support +Organization: Addiva Elektronik + +Add support for attaching mqprio qdisc's to mv88e6xxx ports and use +the packet's traffic class as the outgoing priority when no PCP bits +are available. + +We cannot directly target a particular transmit queue on mv88e6xxx +chips, we can only specify the frame priority (FPri), which will +typically cause the switch to set the packet's queue priority (QPri) +to the same value. + +For symmetry, we give precedence to an explicit PCP value available in +the packet, since that maps directly to the chip's FPri. + +In cases where no PCP bits are available, use the packet's queue +mapping to derive its traffic class and use that as the FPri. Since +the packet will always be egressing without a tag in these cases, we +are effectively only specifying the QPri. + +Since FPri is always a 3-bit field, even on older chips with only 4 +physical queues, always report 8 queues and let the chip's policy +handle the mapping down to the "real" number. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 70 ++++++++++++++++++++++++++++++++ + net/dsa/tag_dsa.c | 4 +- + 2 files changed, 73 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 3151df2a27c7..f50ad71bb28b 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include "chip.h" + #include "devlink.h" +@@ -7126,6 +7127,68 @@ static int mv88e6xxx_port_del_etype_prio(struct dsa_switch *ds, int port, + return err; + } + ++static int mv88e6xxx_qos_port_mqprio(struct mv88e6xxx_chip *chip, int port, ++ struct tc_mqprio_qopt_offload *mqprio) ++{ ++ struct net_device *dev = dsa_to_port(chip->ds, port)->user; ++ struct tc_mqprio_qopt *qopt = &mqprio->qopt; ++ int tc, err = 0, num_txq = 0; ++ ++ if (!qopt->num_tc) ++ goto out_reset; ++ ++ err = netdev_set_num_tc(dev, qopt->num_tc); ++ if (err) ++ return err; ++ ++ for (tc = 0; tc < qopt->num_tc; tc++) { ++ num_txq += qopt->count[tc]; ++ ++ err = netdev_set_tc_queue(dev, tc, qopt->count[tc], qopt->offset[tc]); ++ if (err) ++ goto out_reset; ++ } ++ ++ err = netif_set_real_num_tx_queues(dev, num_txq); ++ if (err) ++ goto out_reset; ++ ++ return 0; ++ ++out_reset: ++ netdev_reset_tc(dev); ++ return err; ++ ++} ++ ++static int mv88e6xxx_qos_query_caps(struct tc_query_caps_base *base) ++{ ++ switch (base->type) { ++ case TC_SETUP_QDISC_MQPRIO: ++ struct tc_mqprio_caps *caps = base->caps; ++ ++ caps->validate_queue_counts = true; ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++static int mv88e6xxx_port_setup_tc(struct dsa_switch *ds, int port, ++ enum tc_setup_type type, ++ void *type_data) ++{ ++ struct mv88e6xxx_chip *chip = ds->priv; ++ ++ switch (type) { ++ case TC_QUERY_CAPS: ++ return mv88e6xxx_qos_query_caps(type_data); ++ case TC_SETUP_QDISC_MQPRIO: ++ return mv88e6xxx_qos_port_mqprio(chip, port, type_data); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ + static const struct phylink_mac_ops mv88e6xxx_phylink_mac_ops = { + .mac_select_pcs = mv88e6xxx_mac_select_pcs, + .mac_prepare = mv88e6xxx_mac_prepare, +@@ -7197,6 +7260,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { + .crosschip_lag_leave = mv88e6xxx_crosschip_lag_leave, + .port_add_etype_prio = mv88e6xxx_port_add_etype_prio, + .port_del_etype_prio = mv88e6xxx_port_del_etype_prio, ++ .port_setup_tc = mv88e6xxx_port_setup_tc, + }; + + static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) +@@ -7223,6 +7287,12 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) + */ + ds->num_lag_ids = mv88e6xxx_has_lag(chip) ? 16 : 0; + ++ /* Even though older chips only have 4 queues, we always have ++ * 3 bits of priority information in the DSA tag, which is how ++ * we indirectly address the queues. ++ */ ++ ds->num_tx_queues = 8; ++ + dev_set_drvdata(dev, ds); + + return dsa_register_switch(ds); +diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c +index a00ae6bf2971..55c296e0b5b0 100644 +--- a/net/dsa/tag_dsa.c ++++ b/net/dsa/tag_dsa.c +@@ -180,8 +180,10 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev, + } + } else { + u16 vid; ++ u8 tc; + + vid = br_dev ? MV88E6XXX_VID_BRIDGED : MV88E6XXX_VID_STANDALONE; ++ tc = netdev_txq_to_tc(dev, skb_get_queue_mapping(skb)); + + skb_push(skb, DSA_HLEN + extra); + dsa_alloc_etype_header(skb, DSA_HLEN + extra); +@@ -191,7 +193,7 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev, + + dsa_header[0] = (cmd << 6) | tag_dev; + dsa_header[1] = tag_port << 3; +- dsa_header[2] = vid >> 8; ++ dsa_header[2] = (tc << 5) | (vid >> 8); + dsa_header[3] = vid & 0xff; + } + +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0012-net-dsa-mv88e6xxx-Use-VLAN-prio-over-IP-when-both-ar.patch b/patches/linux/6.12.1/0012-net-dsa-mv88e6xxx-Use-VLAN-prio-over-IP-when-both-ar.patch new file mode 100644 index 00000000..ba7d64c9 --- /dev/null +++ b/patches/linux/6.12.1/0012-net-dsa-mv88e6xxx-Use-VLAN-prio-over-IP-when-both-ar.patch @@ -0,0 +1,62 @@ +From b1f2d857a7457c8c965d281d8c8875ad491670a7 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Wed, 29 May 2024 13:20:41 +0200 +Subject: [PATCH 12/24] net: dsa: mv88e6xxx: Use VLAN prio over IP when both + are available +Organization: Addiva Elektronik + +Switch the priority sourcing precdence to prefer VLAN PCP over IP +DSCP, when both are available. + +Ever since the initial commit of this driver, IP priority (DSCP/TOS) +has instead taken precedence over VLAN priority (PCP) when determining +a packet's initial queue and frame priority (Qpri/Fpri). There are two +main reasons for choosing the new default: + +1. It matches the chip's hardware default settings and thus follows + the principle of least astonishment. + +2. In the typical case where a packet initially ingresses a network on + a UNI port, the first switch will have the most context available + about that flow; and is therefore entrusted to determine the + packet's priority. As the packet then moves through the network + core over trusted VLAN trunks, the packet should keep its original + priority, independent of what inner protocol fields may indicate. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index f50ad71bb28b..2a46bf5f3da8 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -3402,9 +3402,13 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + + /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, + * disable Header mode, enable IGMP/MLD snooping, disable VLAN +- * tunneling, determine priority by looking at 802.1p and IP +- * priority fields (IP prio has precedence), and set STP state +- * to Forwarding. ++ * tunneling, and set STP state to Forwarding. ++ * ++ * Use the following sources of information, in order of ++ * precedence, to determine a packet's initial Qpri/Fpri: ++ * 1. VLAN PCP field, if available ++ * 2. IPv4/6 DSCP field, if available ++ * 3. Ingress port defaults + * + * If this is the CPU link, use DSA or EDSA tagging depending + * on which tagging mode was configured. +@@ -3415,6 +3419,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + * forwarding of unknown unicasts and multicasts. + */ + reg = MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | ++ MV88E6XXX_PORT_CTL0_TAG_IF_BOTH | + MV88E6XXX_PORT_CTL0_STATE_FORWARDING; + /* Forward any IPv4 IGMP or IPv6 MLD frames received + * by a USER port to the CPU port to allow snooping. +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0013-FIX-net-dsa-mv88e6xxx-Trap-locally-terminated-VLANs.patch b/patches/linux/6.12.1/0013-FIX-net-dsa-mv88e6xxx-Trap-locally-terminated-VLANs.patch new file mode 100644 index 00000000..e751ecbb --- /dev/null +++ b/patches/linux/6.12.1/0013-FIX-net-dsa-mv88e6xxx-Trap-locally-terminated-VLANs.patch @@ -0,0 +1,161 @@ +From eedb27bcce73ed62534528bd098b897954f98d3c Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 26 Nov 2024 19:45:59 +0100 +Subject: [PATCH 13/24] [FIX] net: dsa: mv88e6xxx: Trap locally terminated + VLANs +Organization: Addiva Elektronik + +Before this change, in a setup like the following, packets assigned to +VLAN 10 were forwarded between the switch ports, even though the +configuration dictates that they should only be locally terminated. + +ip link add dev br0 up type bridge vlan_filtering 1 +ip link set dev swp1 master br0 +ip link set dev swp2 master br0 +ip link add dev swp1.10 link swp1 up type vlan id 10 +ip link add dev swp2.10 link swp2 up type vlan id 10 + +swp1.10 br0 swp2.10 + \ / \ / + swp1 swp2 + +Therefore, make sure that VLANs that are added to the VTU to terminate +a VLAN upper interface, rather than to offload bridge VLANs, are +marked as policy entries. As the VTU policy of user ports is already +set to TRAP (to ensure proper standalone port operation), this will +cause all packets assigned to these VLANs to properly terminated. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 33 ++++++++++++++++++-------------- + include/net/switchdev.h | 4 ++++ + net/dsa/user.c | 4 ++++ + 3 files changed, 27 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 2a46bf5f3da8..785cd3d0e2b1 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -2631,7 +2631,7 @@ static int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port, + } + + static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, +- u16 vid, u8 member, bool warn) ++ u16 vid, u8 member, bool warn, bool policy) + { + const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; + struct mv88e6xxx_vtu_entry vlan; +@@ -2643,9 +2643,7 @@ static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, + + if (!vlan.valid) { + memset(&vlan, 0, sizeof(vlan)); +- +- if (vid == MV88E6XXX_VID_STANDALONE) +- vlan.policy = true; ++ vlan.policy = policy; + + err = mv88e6xxx_atu_new(chip, &vlan.fid); + if (err) +@@ -2668,6 +2666,9 @@ static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, + if (err) + return err; + } else if (vlan.member[port] != member) { ++ if (vlan.policy != policy) ++ return -EBUSY; ++ + vlan.member[port] = member; + + err = mv88e6xxx_vtu_loadpurge(chip, &vlan); +@@ -2714,7 +2715,8 @@ static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, + + mv88e6xxx_reg_lock(chip); + +- err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn); ++ err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn, ++ vlan->from_upper); + if (err) { + dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, + vlan->vid, untagged ? 'u' : 't'); +@@ -3454,14 +3456,17 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + if (err) + return err; + +- /* On chips that support it, set all downstream DSA ports' +- * VLAN policy to TRAP. In combination with loading +- * MV88E6XXX_VID_STANDALONE as a policy entry in the VTU, this +- * provides a better isolation barrier between standalone +- * ports, as the ATU is bypassed on any intermediate switches +- * between the incoming port and the CPU. ++ /* On chips that support it, set all downstream DSA and user ++ * ports' VLAN policy to TRAP. for downstream DSA ports, in ++ * combination with loading MV88E6XXX_VID_STANDALONE as a ++ * policy entry in the VTU, this provides a better isolation ++ * barrier between standalone ports, as the ATU is bypassed on ++ * any intermediate switches between the incoming port and the ++ * CPU. On user ports we need it to support stacked VLAN ++ * uppers on ports that are simultaneously attached to a VLAN ++ * filtering bridge. + */ +- if (dsa_is_downstream_port(ds, port) && ++ if ((dsa_is_downstream_port(ds, port) || dsa_is_user_port(ds, port)) && + chip->info->ops->port_set_policy) { + err = chip->info->ops->port_set_policy(chip, port, + MV88E6XXX_POLICY_MAPPING_VTU, +@@ -3491,7 +3496,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + */ + err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_STANDALONE, + MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED, +- false); ++ false, true); + if (err) + return err; + +@@ -3505,7 +3510,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + */ + err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED, + MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED, +- false); ++ false, false); + if (err) + return err; + +diff --git a/include/net/switchdev.h b/include/net/switchdev.h +index 8346b0d29542..764cd3dd4645 100644 +--- a/include/net/switchdev.h ++++ b/include/net/switchdev.h +@@ -104,6 +104,10 @@ struct switchdev_obj_port_vlan { + * Entries with BRIDGE_VLAN_INFO_BRENTRY unset are not notified at all. + */ + bool changed; ++ ++ /* If set, this VLAN object stems from an upper interface ++ * being stacked on/removed from the original device. */ ++ bool from_upper; + }; + + #define SWITCHDEV_OBJ_PORT_VLAN(OBJ) \ +diff --git a/net/dsa/user.c b/net/dsa/user.c +index e13fb22e2c2b..f45e313f1dd0 100644 +--- a/net/dsa/user.c ++++ b/net/dsa/user.c +@@ -1754,6 +1754,8 @@ static int dsa_user_vlan_rx_add_vid(struct net_device *dev, __be16 proto, + .vid = vid, + /* This API only allows programming tagged, non-PVID VIDs */ + .flags = 0, ++ ++ .from_upper = true, + }; + struct netlink_ext_ack extack = {0}; + struct dsa_switch *ds = dp->ds; +@@ -1828,6 +1830,8 @@ static int dsa_user_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, + .vid = vid, + /* This API only allows programming tagged, non-PVID VIDs */ + .flags = 0, ++ ++ .from_upper = true, + }; + struct dsa_switch *ds = dp->ds; + struct netdev_hw_addr *ha; +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0014-net-phy-marvell10g-Support-firmware-loading-on-88X33.patch b/patches/linux/6.12.1/0014-net-phy-marvell10g-Support-firmware-loading-on-88X33.patch new file mode 100644 index 00000000..fc232276 --- /dev/null +++ b/patches/linux/6.12.1/0014-net-phy-marvell10g-Support-firmware-loading-on-88X33.patch @@ -0,0 +1,241 @@ +From f84d14369aad6ad2d2aec71dcf907d2ff70aa4fa Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 19 Sep 2023 18:38:10 +0200 +Subject: [PATCH 14/24] net: phy: marvell10g: Support firmware loading on + 88X3310 +Organization: Addiva Elektronik + +When probing, if a device is waiting for firmware to be loaded into +its RAM, ask userspace for the binary and load it over XMDIO. + +We have no choice but to bail out of the probe if firmware is not +available, as the device does not have any built-in image on which to +fall back. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/phy/marvell10g.c | 161 +++++++++++++++++++++++++++++++++++ + 1 file changed, 161 insertions(+) + +diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c +index 6642eb642d4b..79d9483419c0 100644 +--- a/drivers/net/phy/marvell10g.c ++++ b/drivers/net/phy/marvell10g.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -50,6 +51,10 @@ enum { + MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6, + MV_PMA_BOOT = 0xc050, + MV_PMA_BOOT_FATAL = BIT(0), ++ MV_PMA_BOOT_PRGS_MASK = 0x0006, ++ MV_PMA_BOOT_PRGS_WAIT = 0x0002, ++ MV_PMA_BOOT_APP_STARTED = BIT(4), ++ MV_PMA_BOOT_APP_LOADED = BIT(6), + + MV_PCS_BASE_T = 0x0000, + MV_PCS_BASE_R = 0x1000, +@@ -96,6 +101,12 @@ enum { + MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380, + MV_PCS_PORT_INFO_NPORTS_SHIFT = 7, + ++ /* Firmware downloading */ ++ MV_PCS_FW_ADDR_LOW = 0xd0f0, ++ MV_PCS_FW_ADDR_HIGH = 0xd0f1, ++ MV_PCS_FW_DATA = 0xd0f2, ++ MV_PCS_FW_CSUM = 0xd0f3, ++ + /* SerDes reinitialization 88E21X0 */ + MV_AN_21X0_SERDES_CTRL2 = 0x800f, + MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS = BIT(13), +@@ -157,6 +168,8 @@ struct mv3310_chip { + const struct mv3310_mactype *mactypes; + size_t n_mactypes; + ++ const char *firmware_path; ++ + #ifdef CONFIG_HWMON + int (*hwmon_read_temp_reg)(struct phy_device *phydev); + #endif +@@ -508,6 +521,145 @@ static const struct sfp_upstream_ops mv3310_sfp_ops = { + .module_insert = mv3310_sfp_insert, + }; + ++struct mv3310_fw_hdr { ++ __le32 data_size; ++ __le32 data_addr; ++ __le16 data_csum; ++ __le16 flags; ++#define MV3310_FW_HDR_DATA_ONLY BIT(6) ++ __le32 next_hdr; ++ __le16 csum; ++ ++ u8 pad[14]; ++} __packed; ++ ++struct mv3310_fw_sect_info { ++ const u8 *data; ++ u32 size; ++ u32 addr; ++ u16 csum; ++}; ++ ++static int mv3310_load_fw_sect(struct phy_device *phydev, ++ const struct mv3310_fw_sect_info *si) ++{ ++ size_t i; ++ u16 csum; ++ ++ dev_dbg(&phydev->mdio.dev, "Loading %u byte section at 0x%08x\n", ++ si->size, si->addr); ++ ++ for (i = 0, csum = 0; i < si->size; i++) ++ csum += si->data[i]; ++ ++ if ((u16)~csum != si->csum) { ++ dev_err(&phydev->mdio.dev, "Corrupt section data\n"); ++ return -EINVAL; ++ } ++ ++ /* Any existing checksum is cleared by a read */ ++ __phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_CSUM); ++ ++ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_ADDR_LOW, si->addr & 0xffff); ++ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_ADDR_HIGH, si->addr >> 16); ++ ++ for (i = 0; i < si->size; i += 2) { ++ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_DATA, ++ (si->data[i + 1] << 8) | si->data[i]); ++ } ++ ++ csum = __phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_CSUM); ++ if ((u16)~csum != si->csum) { ++ dev_err(&phydev->mdio.dev, "Download failed\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int mv3310_load_fw(struct phy_device *phydev) ++{ ++ const struct mv3310_chip *chip = to_mv3310_chip(phydev); ++ struct mv3310_fw_sect_info si; ++ const struct firmware *fw; ++ struct mv3310_fw_hdr hdr; ++ bool need_boot = false; ++ const u8 *sect; ++ size_t i; ++ u32 next; ++ u16 csum; ++ int err; ++ ++ if (!chip->firmware_path) ++ return -EOPNOTSUPP; ++ ++ err = request_firmware(&fw, chip->firmware_path, &phydev->mdio.dev); ++ if (err) ++ return err; ++ ++ if (fw->size & 1) { ++ err = -EINVAL; ++ goto release; ++ } ++ ++ phy_lock_mdio_bus(phydev); ++ ++ for (sect = fw->data; (sect + sizeof(hdr)) < (fw->data + fw->size);) { ++ memcpy(&hdr, sect, sizeof(hdr)); ++ ++ for (i = 0, csum = 0; i < offsetof(struct mv3310_fw_hdr, csum); i++) ++ csum += sect[i]; ++ ++ if ((u16)~csum != le16_to_cpu(hdr.csum)) { ++ dev_err(&phydev->mdio.dev, "Corrupt section header\n"); ++ err = -EINVAL; ++ goto unlock; ++ } ++ ++ si.data = sect + sizeof(hdr); ++ si.size = le32_to_cpu(hdr.data_size); ++ si.addr = le32_to_cpu(hdr.data_addr); ++ si.csum = le16_to_cpu(hdr.data_csum); ++ ++ if ((si.data + si.size) > (fw->data + fw->size)) { ++ dev_err(&phydev->mdio.dev, "Invalid section length\n"); ++ err = -EINVAL; ++ goto unlock; ++ } ++ ++ err = mv3310_load_fw_sect(phydev, &si); ++ if (err) ++ goto unlock; ++ ++ if (!(le16_to_cpu(hdr.flags) & MV3310_FW_HDR_DATA_ONLY)) ++ need_boot = true; ++ ++ next = le32_to_cpu(hdr.next_hdr); ++ if (!next) ++ break; ++ ++ sect = fw->data + next; ++ } ++ ++ if (need_boot) { ++ __phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT, 0, ++ MV_PMA_BOOT_APP_LOADED); ++ mdelay(200); ++ if (!(__phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT) & ++ MV_PMA_BOOT_APP_STARTED)) { ++ dev_err(&phydev->mdio.dev, "Firmware boot failed\n"); ++ err = -ENODEV; ++ } ++ } ++ ++unlock: ++ phy_unlock_mdio_bus(phydev); ++ ++release: ++ release_firmware(fw); ++ return err; ++} ++ + static int mv3310_probe(struct phy_device *phydev) + { + const struct mv3310_chip *chip = to_mv3310_chip(phydev); +@@ -529,6 +681,12 @@ static int mv3310_probe(struct phy_device *phydev) + return -ENODEV; + } + ++ if ((ret & MV_PMA_BOOT_PRGS_MASK) == MV_PMA_BOOT_PRGS_WAIT) { ++ ret = mv3310_load_fw(phydev); ++ if (ret) ++ return ret; ++ } ++ + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; +@@ -1222,6 +1380,8 @@ static const struct mv3310_chip mv3310_type = { + .mactypes = mv3310_mactypes, + .n_mactypes = ARRAY_SIZE(mv3310_mactypes), + ++ .firmware_path = "mrvl/x3310fw.hdr", ++ + #ifdef CONFIG_HWMON + .hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg, + #endif +@@ -1491,4 +1651,5 @@ static struct mdio_device_id __maybe_unused mv3310_tbl[] = { + }; + MODULE_DEVICE_TABLE(mdio, mv3310_tbl); + MODULE_DESCRIPTION("Marvell Alaska X/M multi-gigabit Ethernet PHY driver"); ++MODULE_FIRMWARE("mrvl/x3310fw.hdr"); + MODULE_LICENSE("GPL"); +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0015-net-phy-marvell10g-Fix-power-up-when-strapped-to-sta.patch b/patches/linux/6.12.1/0015-net-phy-marvell10g-Fix-power-up-when-strapped-to-sta.patch new file mode 100644 index 00000000..b5ef7467 --- /dev/null +++ b/patches/linux/6.12.1/0015-net-phy-marvell10g-Fix-power-up-when-strapped-to-sta.patch @@ -0,0 +1,50 @@ +From 0ffa9ba9b48fbd9f818b8c789202ae85bc401f47 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 21 Nov 2023 20:15:24 +0100 +Subject: [PATCH 15/24] net: phy: marvell10g: Fix power-up when strapped to + start powered down +Organization: Addiva Elektronik + +On devices which are hardware strapped to start powered down (PDSTATE +== 1), make sure that we clear the power-down bit on all units +affected by this setting. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/phy/marvell10g.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c +index 79d9483419c0..268484092776 100644 +--- a/drivers/net/phy/marvell10g.c ++++ b/drivers/net/phy/marvell10g.c +@@ -342,11 +342,23 @@ static int mv3310_power_down(struct phy_device *phydev) + + static int mv3310_power_up(struct phy_device *phydev) + { ++ static const u16 resets[][2] = { ++ { MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_CTRL1 }, ++ { MDIO_MMD_PCS, MV_PCS_BASE_T + MDIO_CTRL1 }, ++ { MDIO_MMD_PMAPMD, MDIO_CTRL1 }, ++ }; + struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); +- int ret; ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(resets); i++) { ++ ret = phy_clear_bits_mmd(phydev, resets[i][0], resets[i][1], ++ MDIO_CTRL1_LPOWER); ++ if (ret) ++ break; ++ } + +- ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, +- MV_V2_PORT_CTRL_PWRDOWN); ++ ret = ret ? : phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, ++ MV_V2_PORT_CTRL_PWRDOWN); + + /* Sometimes, the power down bit doesn't clear immediately, and + * a read of this register causes the bit not to clear. Delay +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0016-net-phy-marvell10g-Add-LED-support-for-88X3310.patch b/patches/linux/6.12.1/0016-net-phy-marvell10g-Add-LED-support-for-88X3310.patch new file mode 100644 index 00000000..f3cab423 --- /dev/null +++ b/patches/linux/6.12.1/0016-net-phy-marvell10g-Add-LED-support-for-88X3310.patch @@ -0,0 +1,517 @@ +From 2c99fab374153c7eac6ba9874d47367871cec640 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Wed, 15 Nov 2023 20:58:42 +0100 +Subject: [PATCH 16/24] net: phy: marvell10g: Add LED support for 88X3310 +Organization: Addiva Elektronik + +Pickup the LEDs from the state in which the hardware reset or +bootloader left them, but also support further configuration via +device tree. This is primarily needed because the electrical polarity +and drive behavior is software controlled and not possible to set via +hardware strapping. + +Trigger support: +- "none" +- "timer": Map 60-100 ms periods to the fast rate (81ms) and 1000-1600 + ms periods to the slow rate (1300ms). Defer everything else to + software blinking +- "netdev": Offload link or duplex information to the solid behavior; + tx and/or rx activity to blink behavior. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/phy/marvell10g.c | 422 +++++++++++++++++++++++++++++++++++ + 1 file changed, 422 insertions(+) + +diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c +index 268484092776..9f8475b67ef7 100644 +--- a/drivers/net/phy/marvell10g.c ++++ b/drivers/net/phy/marvell10g.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -133,6 +134,16 @@ enum { + MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN = 0x5, + MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6, + MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII = 0x7, ++ MV_V2_LED0_CONTROL = 0xf020, ++ MV_V2_LED_CONTROL_POLARITY_MASK = 0x0003, ++ MV_V2_LED_CONTROL_POLARITY_SHIFT = 0, ++ MV_V2_LED_CONTROL_ACTIVE_HIGH = BIT(0), ++ MV_V2_LED_CONTROL_TRISTATE = BIT(1), ++ MV_V2_LED_CONTROL_BLINK_RATE = BIT(2), ++ MV_V2_LED_CONTROL_SOLID_FUNC_MASK = 0x00f8, ++ MV_V2_LED_CONTROL_SOLID_FUNC_SHIFT = 3, ++ MV_V2_LED_CONTROL_BLINK_FUNC_MASK = 0x1f00, ++ MV_V2_LED_CONTROL_BLINK_FUNC_SHIFT = 8, + MV_V2_PORT_INTR_STS = 0xf040, + MV_V2_PORT_INTR_MASK = 0xf043, + MV_V2_PORT_INTR_STS_WOL_EN = BIT(8), +@@ -161,6 +172,7 @@ struct mv3310_mactype { + struct mv3310_chip { + bool (*has_downshift)(struct phy_device *phydev); + void (*init_supported_interfaces)(unsigned long *mask); ++ int (*leds_probe)(struct phy_device *phydev); + int (*get_mactype)(struct phy_device *phydev); + int (*set_mactype)(struct phy_device *phydev, int mactype); + int (*select_mactype)(unsigned long *interfaces); +@@ -175,6 +187,13 @@ struct mv3310_chip { + #endif + }; + ++#define MV3310_N_LEDS 4 ++ ++struct mv3310_led { ++ u8 index; ++ u16 ctrl; ++}; ++ + struct mv3310_priv { + DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX); + const struct mv3310_mactype *mactype; +@@ -184,6 +203,8 @@ struct mv3310_priv { + + struct device *hwmon_dev; + char *hwmon_name; ++ ++ struct mv3310_led led[MV3310_N_LEDS]; + }; + + static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev) +@@ -191,6 +212,396 @@ static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev) + return phydev->drv->driver_data; + } + ++enum mv3310_led_func { ++ MV3310_LED_FUNC_OFF = 0x00, ++ MV3310_LED_FUNC_TX_RX = 0x01, ++ MV3310_LED_FUNC_TX = 0x02, ++ MV3310_LED_FUNC_RX = 0x03, ++ MV3310_LED_FUNC_COLLISION = 0x04, ++ MV3310_LED_FUNC_LINK_COPPER = 0x05, ++ MV3310_LED_FUNC_LINK_FIBER = 0x06, ++ MV3310_LED_FUNC_LINK = 0x07, ++ MV3310_LED_FUNC_10M_LINK = 0x08, ++ MV3310_LED_FUNC_100M_LINK = 0x09, ++ MV3310_LED_FUNC_1G_LINK = 0x0a, ++ MV3310_LED_FUNC_10G_LINK = 0x0b, ++ MV3310_LED_FUNC_10M_100M_LINK = 0x0c, ++ MV3310_LED_FUNC_10M_100M_1G_LINK = 0x0d, ++ MV3310_LED_FUNC_100M_10G_LINK = 0x0e, ++ MV3310_LED_FUNC_1G_10G_LINK = 0x0f, ++ MV3310_LED_FUNC_1G_10G_SLAVE = 0x10, ++ MV3310_LED_FUNC_1G_10G_MASTER = 0x11, ++ MV3310_LED_FUNC_HALF_DUPLEX = 0x12, ++ MV3310_LED_FUNC_FULL_DUPLEX = 0x13, ++ MV3310_LED_FUNC_LINK_EEE = 0x14, ++ MV3310_LED_FUNC_2G5_LINK = 0x15, ++ MV3310_LED_FUNC_5G_LINK = 0x16, ++ MV3310_LED_FUNC_ON = 0x17, ++ MV3310_LED_FUNC_2G5_5G_SLAVE = 0x18, ++ MV3310_LED_FUNC_2G5_5G_MASTER = 0x19, ++ ++ MV3310_LED_FUNC_SPEED_BLINK = 0x1f ++}; ++ ++static int mv3310_led_flags_from_funcs(struct mv3310_led *led, ++ enum mv3310_led_func solid, ++ enum mv3310_led_func blink, ++ unsigned long *flagsp) ++{ ++ unsigned long flags = 0; ++ ++ switch (solid) { ++ case MV3310_LED_FUNC_OFF: ++ break; ++ case MV3310_LED_FUNC_LINK_COPPER: ++ case MV3310_LED_FUNC_LINK_FIBER: ++ case MV3310_LED_FUNC_LINK: ++ flags |= TRIGGER_NETDEV_LINK; ++ break; ++ case MV3310_LED_FUNC_HALF_DUPLEX: ++ flags |= TRIGGER_NETDEV_HALF_DUPLEX; ++ break; ++ case MV3310_LED_FUNC_FULL_DUPLEX: ++ flags |= TRIGGER_NETDEV_FULL_DUPLEX; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (blink) { ++ case MV3310_LED_FUNC_OFF: ++ break; ++ case MV3310_LED_FUNC_TX: ++ flags |= TRIGGER_NETDEV_TX; ++ break; ++ case MV3310_LED_FUNC_RX: ++ flags |= TRIGGER_NETDEV_RX; ++ break; ++ case MV3310_LED_FUNC_TX_RX: ++ flags |= TRIGGER_NETDEV_TX | TRIGGER_NETDEV_RX; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ *flagsp = flags; ++ return 0; ++} ++ ++static int mv3310_led_funcs_from_flags(struct mv3310_led *led, ++ unsigned long flags, ++ enum mv3310_led_func *solid, ++ enum mv3310_led_func *blink) ++{ ++ unsigned long activity, duplex, link; ++ ++ if (flags & ~(BIT(TRIGGER_NETDEV_LINK) | ++ BIT(TRIGGER_NETDEV_HALF_DUPLEX) | ++ BIT(TRIGGER_NETDEV_FULL_DUPLEX) | ++ BIT(TRIGGER_NETDEV_TX) | ++ BIT(TRIGGER_NETDEV_RX))) ++ return -EINVAL; ++ ++ link = flags & BIT(TRIGGER_NETDEV_LINK); ++ ++ duplex = flags & (BIT(TRIGGER_NETDEV_HALF_DUPLEX) | ++ BIT(TRIGGER_NETDEV_FULL_DUPLEX)); ++ ++ activity = flags & (BIT(TRIGGER_NETDEV_TX) | ++ BIT(TRIGGER_NETDEV_RX)); ++ ++ if (link && duplex) ++ return -EINVAL; ++ ++ if (solid) { ++ if (link) { ++ *solid = MV3310_LED_FUNC_LINK; ++ } else if (duplex) { ++ switch (duplex) { ++ case BIT(TRIGGER_NETDEV_HALF_DUPLEX): ++ *solid = MV3310_LED_FUNC_HALF_DUPLEX; ++ break; ++ case BIT(TRIGGER_NETDEV_FULL_DUPLEX): ++ *solid = MV3310_LED_FUNC_FULL_DUPLEX; ++ break; ++ default: ++ break; ++ } ++ } else { ++ *solid = MV3310_LED_FUNC_OFF; ++ } ++ } ++ ++ if (blink) { ++ switch (activity) { ++ case 0: ++ *blink = MV3310_LED_FUNC_OFF; ++ break; ++ case BIT(TRIGGER_NETDEV_TX): ++ *blink = MV3310_LED_FUNC_TX; ++ break; ++ case BIT(TRIGGER_NETDEV_RX): ++ *blink = MV3310_LED_FUNC_RX; ++ break; ++ default: ++ *blink = MV3310_LED_FUNC_TX_RX; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static int mv3310_led_get(struct phy_device *phydev, ++ struct mv3310_led *led, ++ enum mv3310_led_func *solid, ++ enum mv3310_led_func *blink, ++ bool *slow_blink) ++{ ++ int ctrl; ++ ++ ctrl = phy_read_mmd(phydev, MDIO_MMD_VEND2, ++ MV_V2_LED0_CONTROL + led->index); ++ if (ctrl < 0) ++ return ctrl; ++ ++ *solid = (ctrl & MV_V2_LED_CONTROL_SOLID_FUNC_MASK) >> ++ MV_V2_LED_CONTROL_SOLID_FUNC_SHIFT; ++ *blink = (ctrl & MV_V2_LED_CONTROL_BLINK_FUNC_MASK) >> ++ MV_V2_LED_CONTROL_BLINK_FUNC_SHIFT; ++ ++ *slow_blink = !!(ctrl & MV_V2_LED_CONTROL_BLINK_RATE); ++ return 0; ++} ++ ++static int mv3310_led_set(struct phy_device *phydev, ++ struct mv3310_led *led, ++ enum mv3310_led_func solid, ++ enum mv3310_led_func blink, ++ bool slow_blink) ++{ ++ u16 ctrl = led->ctrl; ++ ++ ctrl &= ~MV_V2_LED_CONTROL_SOLID_FUNC_MASK; ++ ctrl &= ~MV_V2_LED_CONTROL_BLINK_FUNC_MASK; ++ ctrl &= ~MV_V2_LED_CONTROL_BLINK_RATE; ++ ++ ctrl |= solid << MV_V2_LED_CONTROL_SOLID_FUNC_SHIFT; ++ ctrl |= blink << MV_V2_LED_CONTROL_BLINK_FUNC_SHIFT; ++ ++ if (slow_blink) ++ ctrl |= MV_V2_LED_CONTROL_BLINK_RATE; ++ ++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, ++ MV_V2_LED0_CONTROL + led->index, ctrl); ++} ++ ++static int mv3310_led_polarity_set(struct phy_device *phydev, ++ int index, unsigned long modes) ++{ ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++ struct mv3310_led *led; ++ u16 ctrl; ++ int err; ++ ++ if (index < 0 || index >= MV3310_N_LEDS) ++ return -ENODEV; ++ ++ led = &priv->led[index]; ++ ctrl = led->ctrl; ++ ++ if (test_bit(PHY_LED_ACTIVE_LOW, &modes)) ++ ctrl &= ~MV_V2_LED_CONTROL_ACTIVE_HIGH; ++ else ++ ctrl |= MV_V2_LED_CONTROL_ACTIVE_HIGH; ++ ++ if (test_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes)) ++ ctrl |= MV_V2_LED_CONTROL_TRISTATE; ++ else ++ ctrl &= ~MV_V2_LED_CONTROL_TRISTATE; ++ ++ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, ++ MV_V2_LED0_CONTROL + index, ctrl); ++ if (err) ++ return err; ++ ++ led->ctrl = ctrl; ++ return 0; ++} ++ ++static int mv3310_led_brightness_set(struct phy_device *phydev, ++ u8 index, enum led_brightness value) ++{ ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++ enum mv3310_led_func solid; ++ struct mv3310_led *led; ++ ++ if (index >= MV3310_N_LEDS) ++ return -ENODEV; ++ ++ led = &priv->led[index]; ++ ++ if (value == LED_OFF) ++ solid = MV3310_LED_FUNC_OFF; ++ else ++ solid = MV3310_LED_FUNC_ON; ++ ++ return mv3310_led_set(phydev, led, solid, MV3310_LED_FUNC_OFF, false); ++} ++ ++static int mv3310_led_blink_set(struct phy_device *phydev, u8 index, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++ struct mv3310_led *led; ++ bool slow_blink; ++ int err; ++ ++ if (index >= MV3310_N_LEDS) ++ return -ENODEV; ++ ++ led = &priv->led[index]; ++ ++ if (*delay_on != *delay_off) ++ /* Defer anything other than 50% duty cycles to ++ * software. ++ */ ++ return -EINVAL; ++ ++ /* Accept values within ~20% of our supported rates (80ms or ++ * 1300ms periods). ++ */ ++ if ((*delay_on >= 30) && (*delay_on <= 50)) ++ slow_blink = false; ++ else if (((*delay_on >= 500) && (*delay_on <= 800)) || (*delay_on == 0)) ++ slow_blink = true; ++ else ++ return -EINVAL; ++ ++ err = mv3310_led_set(phydev, led, MV3310_LED_FUNC_OFF, ++ MV3310_LED_FUNC_ON, slow_blink); ++ if (!err) ++ *delay_on = *delay_off = slow_blink ? 650 : 40; ++ ++ return err; ++} ++ ++static int mv3310_led_hw_is_supported(struct phy_device *phydev, u8 index, ++ unsigned long flags) ++{ ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++ struct mv3310_led *led; ++ ++ if (index >= MV3310_N_LEDS) ++ return -ENODEV; ++ ++ led = &priv->led[index]; ++ ++ return mv3310_led_funcs_from_flags(led, flags, NULL, NULL); ++} ++ ++static int mv3310_led_hw_control_set(struct phy_device *phydev, u8 index, ++ unsigned long flags) ++{ ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++ enum mv3310_led_func solid, blink; ++ struct mv3310_led *led; ++ int err; ++ ++ if (index >= MV3310_N_LEDS) ++ return -ENODEV; ++ ++ led = &priv->led[index]; ++ ++ err = mv3310_led_funcs_from_flags(led, flags, &solid, &blink); ++ if (err) ++ return err; ++ ++ return mv3310_led_set(phydev, led, solid, blink, false); ++} ++ ++static int mv3310_led_hw_control_get(struct phy_device *phydev, u8 index, ++ unsigned long *flags) ++{ ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++ enum mv3310_led_func solid, blink; ++ struct mv3310_led *led; ++ bool slow_blink; ++ int err; ++ ++ if (index >= MV3310_N_LEDS) ++ return -ENODEV; ++ ++ led = &priv->led[index]; ++ ++ err = mv3310_led_get(phydev, led, &solid, &blink, &slow_blink); ++ if (err) ++ return err; ++ ++ return mv3310_led_flags_from_funcs(led, solid, blink, flags); ++} ++ ++static int mv3310_led_probe_of(struct phy_device *phydev, ++ struct device_node *np) ++{ ++ u32 index; ++ int err; ++ ++ err = of_property_read_u32(np, "reg", &index); ++ if (err) ++ return err; ++ ++ if (index >= MV3310_N_LEDS) ++ return -EINVAL; ++ ++ /* mv3310_led_polarity_set() will not be called unless the ++ * device tree specifies a mode that of_phy_led() considers to ++ * be a non-default configuration. I.e., something other than ++ * (active-high, drive low on inactive). But the 3310's HW ++ * default is (active-low, drive low on inactive). Therefore, ++ * configure all LEDs defined in the DT with the kernel ++ * defaults, and then let of_phy_led() set the final value if ++ * the config deviates from that. ++ */ ++ return mv3310_led_polarity_set(phydev, index, 0); ++} ++ ++static int mv3310_leds_probe(struct phy_device *phydev) ++{ ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++ struct device_node *node = phydev->mdio.dev.of_node; ++ struct device_node *pnp, *np; ++ int err, val, index; ++ ++ for (index = 0; index < MV3310_N_LEDS; index++) { ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, ++ MV_V2_LED0_CONTROL + index); ++ if (val < 0) ++ return val; ++ ++ priv->led[index] = (struct mv3310_led) { ++ .index = index, ++ .ctrl = val, ++ }; ++ } ++ ++ if (!node) ++ return 0; ++ ++ pnp = of_get_child_by_name(node, "leds"); ++ if (!pnp) ++ return 0; ++ ++ for_each_available_child_of_node(pnp, np) { ++ err = mv3310_led_probe_of(phydev, np); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ + #ifdef CONFIG_HWMON + static umode_t mv3310_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, +@@ -733,6 +1144,10 @@ static int mv3310_probe(struct phy_device *phydev) + if (ret) + return ret; + ++ ret = chip->leds_probe ? chip->leds_probe(phydev) : 0; ++ if (ret) ++ return ret; ++ + chip->init_supported_interfaces(priv->supported_interfaces); + + return phy_sfp_probe(phydev, &mv3310_sfp_ops); +@@ -1385,6 +1800,7 @@ static void mv2111_init_supported_interfaces(unsigned long *mask) + static const struct mv3310_chip mv3310_type = { + .has_downshift = mv3310_has_downshift, + .init_supported_interfaces = mv3310_init_supported_interfaces, ++ .leds_probe = mv3310_leds_probe, + .get_mactype = mv3310_get_mactype, + .set_mactype = mv3310_set_mactype, + .select_mactype = mv3310_select_mactype, +@@ -1594,6 +2010,12 @@ static struct phy_driver mv3310_drivers[] = { + .set_loopback = genphy_c45_loopback, + .get_wol = mv3110_get_wol, + .set_wol = mv3110_set_wol, ++ .led_polarity_set = mv3310_led_polarity_set, ++ .led_brightness_set = mv3310_led_brightness_set, ++ .led_blink_set = mv3310_led_blink_set, ++ .led_hw_is_supported = mv3310_led_hw_is_supported, ++ .led_hw_control_set = mv3310_led_hw_control_set, ++ .led_hw_control_get = mv3310_led_hw_control_get, + }, + { + .phy_id = MARVELL_PHY_ID_88X3310, +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0017-net-phy-marvell10g-Support-LEDs-tied-to-a-single-med.patch b/patches/linux/6.12.1/0017-net-phy-marvell10g-Support-LEDs-tied-to-a-single-med.patch new file mode 100644 index 00000000..934db5ac --- /dev/null +++ b/patches/linux/6.12.1/0017-net-phy-marvell10g-Support-LEDs-tied-to-a-single-med.patch @@ -0,0 +1,80 @@ +From 6dd8ed1ea83d55469e20b9c13b41810fc2e29af4 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 12 Dec 2023 09:51:05 +0100 +Subject: [PATCH 17/24] net: phy: marvell10g: Support LEDs tied to a single + media side +Organization: Addiva Elektronik + +In a combo-port setup, i.e. where both the copper and fiber interface +are available to the user, the LEDs may be physically located either +by the RJ45 jack, or by an SFP cage. + +For those scenarios, allow the device tree to indicate that an LED is +tied to a particular media side, and use that information to refine +the offloading of the "netdev" trigger, such that LEDs attached to the +RJ45 jack only lights up when a copper link is established, and vice +versa for the SFP cage. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/phy/marvell10g.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c +index 9f8475b67ef7..82b2e9b55b67 100644 +--- a/drivers/net/phy/marvell10g.c ++++ b/drivers/net/phy/marvell10g.c +@@ -192,6 +192,9 @@ struct mv3310_chip { + struct mv3310_led { + u8 index; + u16 ctrl; ++ ++ unsigned copper:1; ++ unsigned fiber:1; + }; + + struct mv3310_priv { +@@ -315,7 +318,12 @@ static int mv3310_led_funcs_from_flags(struct mv3310_led *led, + + if (solid) { + if (link) { +- *solid = MV3310_LED_FUNC_LINK; ++ if (led->copper) ++ *solid = MV3310_LED_FUNC_LINK_COPPER; ++ else if (led->fiber) ++ *solid = MV3310_LED_FUNC_LINK_FIBER; ++ else ++ *solid = MV3310_LED_FUNC_LINK; + } else if (duplex) { + switch (duplex) { + case BIT(TRIGGER_NETDEV_HALF_DUPLEX): +@@ -545,6 +553,9 @@ static int mv3310_led_hw_control_get(struct phy_device *phydev, u8 index, + static int mv3310_led_probe_of(struct phy_device *phydev, + struct device_node *np) + { ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++ struct mv3310_led *led; ++ const char *media; + u32 index; + int err; + +@@ -555,6 +566,16 @@ static int mv3310_led_probe_of(struct phy_device *phydev, + if (index >= MV3310_N_LEDS) + return -EINVAL; + ++ led = &priv->led[index]; ++ ++ err = of_property_read_string(np, "marvell,media", &media); ++ if (!err) { ++ if (!strcmp(media, "copper")) ++ led->copper = 1; ++ else if (!strcmp(media, "fiber")) ++ led->fiber = 1; ++ } ++ + /* mv3310_led_polarity_set() will not be called unless the + * device tree specifies a mode that of_phy_led() considers to + * be a non-default configuration. I.e., something other than +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0018-net-phy-Do-not-resume-PHY-when-attaching.patch b/patches/linux/6.12.1/0018-net-phy-Do-not-resume-PHY-when-attaching.patch new file mode 100644 index 00000000..7546b99b --- /dev/null +++ b/patches/linux/6.12.1/0018-net-phy-Do-not-resume-PHY-when-attaching.patch @@ -0,0 +1,38 @@ +From 17cfde24d88c30c303659f2d8f488c2717592422 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Wed, 27 Mar 2024 10:10:19 +0100 +Subject: [PATCH 18/24] net: phy: Do not resume PHY when attaching +Organization: Addiva Elektronik + +The PHY should not start negotiating with its link-partner until +explicitly instructed to do so. + +Therefore, skip resuming the PHY in the attach phase, deferring it to +when phy_start() is called from the net_device's open() callback, +possibly via phylink_start(). + +Otherwise, drivers that attached to their PHYs during +probing (e.g. DSA) would end up with a physical link being +established, even though the corresponding interface was still +administratively down. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/phy/phy_device.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 499797646580..0acfef4fe43e 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1634,7 +1634,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + if (err) + goto error; + +- phy_resume(phydev); + if (!phydev->is_on_sfp_module) + phy_led_triggers_register(phydev); + +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0019-net-bridge-avoid-classifying-unknown-multicast-as-mr.patch b/patches/linux/6.12.1/0019-net-bridge-avoid-classifying-unknown-multicast-as-mr.patch new file mode 100644 index 00000000..21d90568 --- /dev/null +++ b/patches/linux/6.12.1/0019-net-bridge-avoid-classifying-unknown-multicast-as-mr.patch @@ -0,0 +1,237 @@ +From c75c32e677f22caf857981d1c8a3f580bf367230 Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Mon, 4 Mar 2024 16:47:28 +0100 +Subject: [PATCH 19/24] net: bridge: avoid classifying unknown multicast as + mrouters_only +Organization: Addiva Elektronik + +Unknown multicast, MAC/IPv4/IPv6, should always be flooded according to +the per-port mcast_flood setting, as well as to detected and configured +mcast_router ports. + +This patch drops the mrouters_only classifier of unknown IP multicast +and moves the flow handling from br_multicast_flood() to br_flood(). +This in turn means br_flood() must know about multicast router ports. +Because a multicast router should always receive both known and unknown +multicast. + +Signed-off-by: Joachim Wiberg +Signed-off-by: Tobias Waldekranz +--- + include/uapi/linux/if_bridge.h | 1 + + net/bridge/br.c | 5 +++++ + net/bridge/br_device.c | 10 ++++++---- + net/bridge/br_forward.c | 14 ++++++++++++-- + net/bridge/br_input.c | 2 +- + net/bridge/br_multicast.c | 11 +++++++++-- + net/bridge/br_private.h | 18 ++++++++++++++++-- + 7 files changed, 50 insertions(+), 11 deletions(-) + +diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h +index a5b743a2f775..3bffc39d7800 100644 +--- a/include/uapi/linux/if_bridge.h ++++ b/include/uapi/linux/if_bridge.h +@@ -830,6 +830,7 @@ enum br_boolopt_id { + BR_BOOLOPT_NO_LL_LEARN, + BR_BOOLOPT_MCAST_VLAN_SNOOPING, + BR_BOOLOPT_MST_ENABLE, ++ BR_BOOLOPT_MCAST_FLOOD_ALWAYS, + BR_BOOLOPT_MAX + }; + +diff --git a/net/bridge/br.c b/net/bridge/br.c +index 2cab878e0a39..006fb2e5eafb 100644 +--- a/net/bridge/br.c ++++ b/net/bridge/br.c +@@ -277,6 +277,9 @@ int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on, + case BR_BOOLOPT_MST_ENABLE: + err = br_mst_set_enabled(br, on, extack); + break; ++ case BR_BOOLOPT_MCAST_FLOOD_ALWAYS: ++ br_opt_toggle(br, BROPT_MCAST_FLOOD_ALWAYS, on); ++ break; + default: + /* shouldn't be called with unsupported options */ + WARN_ON(1); +@@ -295,6 +298,8 @@ int br_boolopt_get(const struct net_bridge *br, enum br_boolopt_id opt) + return br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED); + case BR_BOOLOPT_MST_ENABLE: + return br_opt_get(br, BROPT_MST_ENABLED); ++ case BR_BOOLOPT_MCAST_FLOOD_ALWAYS: ++ return br_opt_get(br, BROPT_MCAST_FLOOD_ALWAYS); + default: + /* shouldn't be called with unsupported options */ + WARN_ON(1); +diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c +index 26b79feb385d..f3ecc70a47dc 100644 +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -87,10 +87,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) + + dest = eth_hdr(skb)->h_dest; + if (is_broadcast_ether_addr(dest)) { +- br_flood(br, skb, BR_PKT_BROADCAST, false, true, vid); ++ br_flood(br, skb, NULL, BR_PKT_BROADCAST, false, true, vid); + } else if (is_multicast_ether_addr(dest)) { + if (unlikely(netpoll_tx_running(dev))) { +- br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid); ++ br_flood(br, skb, brmctx, BR_PKT_MULTICAST, false, true, vid); + goto out; + } + if (br_multicast_rcv(&brmctx, &pmctx_null, vlan, skb, vid)) { +@@ -103,11 +103,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) + br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) + br_multicast_flood(mdst, skb, brmctx, false, true); + else +- br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid); ++ br_flood(br, skb, brmctx, BR_PKT_MULTICAST, false, true, vid); + } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { + br_forward(dst->dst, skb, false, true); + } else { +- br_flood(br, skb, BR_PKT_UNICAST, false, true, vid); ++ br_flood(br, skb, NULL, BR_PKT_UNICAST, false, true, vid); + } + out: + rcu_read_unlock(); +@@ -526,6 +526,8 @@ void br_dev_setup(struct net_device *dev) + br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME; + dev->max_mtu = ETH_MAX_MTU; + ++ br_opt_toggle(br, BROPT_MCAST_FLOOD_ALWAYS, false); ++ + br_netfilter_rtable_init(br); + br_stp_timer_init(br); + br_multicast_init(br); +diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c +index e19b583ff2c6..1094364d96e0 100644 +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -198,14 +198,19 @@ static struct net_bridge_port *maybe_deliver( + + /* called under rcu_read_lock */ + void br_flood(struct net_bridge *br, struct sk_buff *skb, +- enum br_pkt_type pkt_type, bool local_rcv, bool local_orig, +- u16 vid) ++ struct net_bridge_mcast *brmctx, enum br_pkt_type pkt_type, ++ bool local_rcv, bool local_orig, u16 vid) + { ++ struct net_bridge_port *rport = NULL; + struct net_bridge_port *prev = NULL; ++ struct hlist_node *rp = NULL; + struct net_bridge_port *p; + + br_tc_skb_miss_set(skb, pkt_type != BR_PKT_BROADCAST); + ++ if (pkt_type == BR_PKT_MULTICAST) ++ rp = br_multicast_get_first_rport_node(brmctx, skb); ++ + list_for_each_entry_rcu(p, &br->port_list, list) { + /* Do not flood unicast traffic to ports that turn it off, nor + * other traffic if flood off, except for traffic we originate +@@ -216,6 +221,11 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb, + continue; + break; + case BR_PKT_MULTICAST: ++ rport = br_multicast_rport_from_node_skb(rp, skb); ++ if (rport == p) { ++ rp = rcu_dereference(hlist_next_rcu(rp)); ++ break; ++ } + if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) + continue; + break; +diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c +index ceaa5a89b947..e54d648db7de 100644 +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -212,7 +212,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb + br_forward(dst->dst, skb, local_rcv, false); + } else { + if (!mcast_hit) +- br_flood(br, skb, pkt_type, local_rcv, false, vid); ++ br_flood(br, skb, brmctx, pkt_type, local_rcv, false, vid); + else + br_multicast_flood(mdst, skb, brmctx, local_rcv, false); + } +diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c +index b2ae0d2434d2..3137c1fcfc6a 100644 +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -3774,6 +3774,11 @@ static void br_multicast_err_count(const struct net_bridge *br, + u64_stats_update_end(&pstats->syncp); + } + ++static bool br_flood_mrouters(const struct net_bridge *br) ++{ ++ return br_opt_get(br, BROPT_MCAST_FLOOD_ALWAYS) ? false : true; ++} ++ + static void br_multicast_pim(struct net_bridge_mcast *brmctx, + struct net_bridge_mcast_port *pmctx, + const struct sk_buff *skb) +@@ -3820,7 +3825,8 @@ static int br_multicast_ipv4_rcv(struct net_bridge_mcast *brmctx, + + if (err == -ENOMSG) { + if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) { +- BR_INPUT_SKB_CB(skb)->mrouters_only = 1; ++ BR_INPUT_SKB_CB(skb)->mrouters_only = ++ br_flood_mrouters(brmctx->br); + } else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) { + if (ip_hdr(skb)->protocol == IPPROTO_PIM) + br_multicast_pim(brmctx, pmctx, skb); +@@ -3889,7 +3895,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge_mcast *brmctx, + + if (err == -ENOMSG || err == -ENODATA) { + if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr)) +- BR_INPUT_SKB_CB(skb)->mrouters_only = 1; ++ BR_INPUT_SKB_CB(skb)->mrouters_only = ++ br_flood_mrouters(brmctx->br); + if (err == -ENODATA && + ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr)) + br_ip6_multicast_mrd_rcv(brmctx, pmctx, skb); +diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h +index 041f6e571a20..40651b07df94 100644 +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -483,6 +483,7 @@ enum net_bridge_opts { + BROPT_VLAN_BRIDGE_BINDING, + BROPT_MCAST_VLAN_SNOOPING_ENABLED, + BROPT_MST_ENABLED, ++ BROPT_MCAST_FLOOD_ALWAYS, + }; + + struct net_bridge { +@@ -886,8 +887,8 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, + bool local_rcv, bool local_orig); + int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb); + void br_flood(struct net_bridge *br, struct sk_buff *skb, +- enum br_pkt_type pkt_type, bool local_rcv, bool local_orig, +- u16 vid); ++ struct net_bridge_mcast *brmctx, enum br_pkt_type pkt_type, ++ bool local_rcv, bool local_orig, u16 vid); + + /* return true if both source port and dest port are isolated */ + static inline bool br_skb_isolated(const struct net_bridge_port *to, +@@ -1408,6 +1409,19 @@ static inline void br_multicast_flood(struct net_bridge_mdb_entry *mdst, + { + } + ++static inline struct hlist_node * ++br_multicast_get_first_rport_node(struct net_bridge_mcast *brmctx, ++ struct sk_buff *skb) ++{ ++ return NULL; ++} ++ ++static inline struct net_bridge_port * ++br_multicast_rport_from_node_skb(struct hlist_node *rp, struct sk_buff *skb) ++{ ++ return NULL; ++} ++ + static inline bool br_multicast_is_router(struct net_bridge_mcast *brmctx, + struct sk_buff *skb) + { +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0020-net-bridge-Ignore-router-ports-when-forwarding-L2-mu.patch b/patches/linux/6.12.1/0020-net-bridge-Ignore-router-ports-when-forwarding-L2-mu.patch new file mode 100644 index 00000000..9946f7f7 --- /dev/null +++ b/patches/linux/6.12.1/0020-net-bridge-Ignore-router-ports-when-forwarding-L2-mu.patch @@ -0,0 +1,37 @@ +From d8c84564a7ef2a5faf4caf76ed797131967258bb Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Tue, 5 Mar 2024 06:44:41 +0100 +Subject: [PATCH 20/24] net: bridge: Ignore router ports when forwarding L2 + multicast +Organization: Addiva Elektronik + +Multicast router ports are either statically configured or learned from +control protocol traffic (IGMP/MLD/PIM). These protocols regulate IP +multicast -- MAC multicast should always be forwarded through flooding +of unknown multicast or using permanent MDB entries. + +Signed-off-by: Tobias Waldekranz +Signed-off-by: Joachim Wiberg +--- + net/bridge/br_private.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h +index 40651b07df94..e90b4f5cab76 100644 +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -1086,7 +1086,10 @@ br_multicast_get_first_rport_node(struct net_bridge_mcast *brmctx, + if (skb->protocol == htons(ETH_P_IPV6)) + return rcu_dereference(hlist_first_rcu(&brmctx->ip6_mc_router_list)); + #endif +- return rcu_dereference(hlist_first_rcu(&brmctx->ip4_mc_router_list)); ++ if (skb->protocol == htons(ETH_P_IP)) ++ return rcu_dereference(hlist_first_rcu(&brmctx->ip4_mc_router_list)); ++ ++ return NULL; + } + + static inline struct net_bridge_port * +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0021-net-bridge-drop-delay-for-applying-strict-multicast-.patch b/patches/linux/6.12.1/0021-net-bridge-drop-delay-for-applying-strict-multicast-.patch new file mode 100644 index 00000000..48373f86 --- /dev/null +++ b/patches/linux/6.12.1/0021-net-bridge-drop-delay-for-applying-strict-multicast-.patch @@ -0,0 +1,191 @@ +From bc2cbf4dd3c5a756e949f6abe7ffc7fe16e499d6 Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Thu, 4 Apr 2024 16:36:30 +0200 +Subject: [PATCH 21/24] net: bridge: drop delay for applying strict multicast + filtering +Organization: Addiva Elektronik + +This *local* patch drops the initial delay before applying strict multicast +filtering, introduced in [1] and recently updated in [2]. + +The main reason for this patch is RFC conformance and customer expectations. +At power on we assume the querier role by default and are expected to stop +unknown flooding as soon as we have a membership report in place, not after +10 seconds. + +A proper fix for upstreaming could be to add a knob to disable the delay. + +[1]: https://lore.kernel.org/netdev/1375311980-25575-1-git-send-email-linus.luessing@web.de/ +[2]: https://lore.kernel.org/netdev/20240127175033.9640-1-linus.luessing@c0d3.blue/ + +Signed-off-by: Joachim Wiberg +Signed-off-by: Tobias Waldekranz +--- + net/bridge/br_multicast.c | 42 +++++++-------------------------------- + net/bridge/br_private.h | 4 +--- + 2 files changed, 8 insertions(+), 38 deletions(-) + +diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c +index 3137c1fcfc6a..34be07a1fd00 100644 +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -1762,10 +1762,6 @@ static void br_ip6_multicast_querier_expired(struct timer_list *t) + } + #endif + +-static void br_multicast_query_delay_expired(struct timer_list *t) +-{ +-} +- + static void br_multicast_select_own_querier(struct net_bridge_mcast *brmctx, + struct br_ip *ip, + struct sk_buff *skb) +@@ -3196,12 +3192,8 @@ int br_multicast_dump_querier_state(struct sk_buff *skb, + + static void + br_multicast_update_query_timer(struct net_bridge_mcast *brmctx, +- struct bridge_mcast_other_query *query, +- unsigned long max_delay) ++ struct bridge_mcast_other_query *query) + { +- if (!timer_pending(&query->timer)) +- mod_timer(&query->delay_timer, jiffies + max_delay); +- + mod_timer(&query->timer, jiffies + brmctx->multicast_querier_interval); + } + +@@ -3392,13 +3384,12 @@ static void + br_ip4_multicast_query_received(struct net_bridge_mcast *brmctx, + struct net_bridge_mcast_port *pmctx, + struct bridge_mcast_other_query *query, +- struct br_ip *saddr, +- unsigned long max_delay) ++ struct br_ip *saddr) + { + if (!br_multicast_select_querier(brmctx, pmctx, saddr)) + return; + +- br_multicast_update_query_timer(brmctx, query, max_delay); ++ br_multicast_update_query_timer(brmctx, query); + br_ip4_multicast_mark_router(brmctx, pmctx); + } + +@@ -3407,13 +3398,12 @@ static void + br_ip6_multicast_query_received(struct net_bridge_mcast *brmctx, + struct net_bridge_mcast_port *pmctx, + struct bridge_mcast_other_query *query, +- struct br_ip *saddr, +- unsigned long max_delay) ++ struct br_ip *saddr) + { + if (!br_multicast_select_querier(brmctx, pmctx, saddr)) + return; + +- br_multicast_update_query_timer(brmctx, query, max_delay); ++ br_multicast_update_query_timer(brmctx, query); + br_ip6_multicast_mark_router(brmctx, pmctx); + } + #endif +@@ -3467,7 +3457,7 @@ static void br_ip4_multicast_query(struct net_bridge_mcast *brmctx, + + br_ip4_multicast_query_received(brmctx, pmctx, + &brmctx->ip4_other_query, +- &saddr, max_delay); ++ &saddr); + goto out; + } + +@@ -3555,7 +3545,7 @@ static int br_ip6_multicast_query(struct net_bridge_mcast *brmctx, + + br_ip6_multicast_query_received(brmctx, pmctx, + &brmctx->ip6_other_query, +- &saddr, max_delay); ++ &saddr); + goto out; + } else if (!group) { + goto out; +@@ -4063,8 +4053,6 @@ void br_multicast_ctx_init(struct net_bridge *br, + br_ip4_multicast_local_router_expired, 0); + timer_setup(&brmctx->ip4_other_query.timer, + br_ip4_multicast_querier_expired, 0); +- timer_setup(&brmctx->ip4_other_query.delay_timer, +- br_multicast_query_delay_expired, 0); + timer_setup(&brmctx->ip4_own_query.timer, + br_ip4_multicast_query_expired, 0); + #if IS_ENABLED(CONFIG_IPV6) +@@ -4072,8 +4060,6 @@ void br_multicast_ctx_init(struct net_bridge *br, + br_ip6_multicast_local_router_expired, 0); + timer_setup(&brmctx->ip6_other_query.timer, + br_ip6_multicast_querier_expired, 0); +- timer_setup(&brmctx->ip6_other_query.delay_timer, +- br_multicast_query_delay_expired, 0); + timer_setup(&brmctx->ip6_own_query.timer, + br_ip6_multicast_query_expired, 0); + #endif +@@ -4208,12 +4194,10 @@ static void __br_multicast_stop(struct net_bridge_mcast *brmctx) + { + del_timer_sync(&brmctx->ip4_mc_router_timer); + del_timer_sync(&brmctx->ip4_other_query.timer); +- del_timer_sync(&brmctx->ip4_other_query.delay_timer); + del_timer_sync(&brmctx->ip4_own_query.timer); + #if IS_ENABLED(CONFIG_IPV6) + del_timer_sync(&brmctx->ip6_mc_router_timer); + del_timer_sync(&brmctx->ip6_other_query.timer); +- del_timer_sync(&brmctx->ip6_other_query.delay_timer); + del_timer_sync(&brmctx->ip6_own_query.timer); + #endif + } +@@ -4641,8 +4625,6 @@ EXPORT_SYMBOL_GPL(br_multicast_router); + + int br_multicast_set_querier(struct net_bridge_mcast *brmctx, unsigned long val) + { +- unsigned long max_delay; +- + val = !!val; + + spin_lock_bh(&brmctx->br->multicast_lock); +@@ -4653,19 +4635,9 @@ int br_multicast_set_querier(struct net_bridge_mcast *brmctx, unsigned long val) + if (!val) + goto unlock; + +- max_delay = brmctx->multicast_query_response_interval; +- +- if (!timer_pending(&brmctx->ip4_other_query.timer)) +- mod_timer(&brmctx->ip4_other_query.delay_timer, +- jiffies + max_delay); +- + br_multicast_start_querier(brmctx, &brmctx->ip4_own_query); + + #if IS_ENABLED(CONFIG_IPV6) +- if (!timer_pending(&brmctx->ip6_other_query.timer)) +- mod_timer(&brmctx->ip6_other_query.delay_timer, +- jiffies + max_delay); +- + br_multicast_start_querier(brmctx, &brmctx->ip6_own_query); + #endif + +diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h +index e90b4f5cab76..73b78c594564 100644 +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -78,7 +78,6 @@ struct bridge_mcast_own_query { + /* other querier */ + struct bridge_mcast_other_query { + struct timer_list timer; +- struct timer_list delay_timer; + }; + + /* selected querier */ +@@ -1164,8 +1163,7 @@ __br_multicast_querier_exists(struct net_bridge_mcast *brmctx, + own_querier_enabled = false; + } + +- return !timer_pending(&querier->delay_timer) && +- (own_querier_enabled || timer_pending(&querier->timer)); ++ return own_querier_enabled || timer_pending(&querier->timer); + } + + static inline bool br_multicast_querier_exists(struct net_bridge_mcast *brmctx, +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0022-net-bridge-Differentiate-MDB-additions-from-modifica.patch b/patches/linux/6.12.1/0022-net-bridge-Differentiate-MDB-additions-from-modifica.patch new file mode 100644 index 00000000..190930fa --- /dev/null +++ b/patches/linux/6.12.1/0022-net-bridge-Differentiate-MDB-additions-from-modifica.patch @@ -0,0 +1,109 @@ +From 65bf34b0195259808333b8fa7b53b8f588c58f32 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Thu, 16 May 2024 14:51:54 +0200 +Subject: [PATCH 22/24] net: bridge: Differentiate MDB additions from + modifications +Organization: Addiva Elektronik + +Before this change, the reception of an IGMPv3 report (and analogously +for MLDv2) that adds a new group, would trigger two MDB RTM_NEWMDB +notifications from br_ip4_multicast_igmp3_report(): + +1. In br_ip4_multicast_add_group() when creating the entry +2. Directly at the end of br_ip4_multicast_igmp3_report(), as the new + group is also deemed to be "changed" + +The corresponding switchdev notifications generated by these present a +problem for drivers wanting to reference count group memberships, +since logically there is only a single reference to the group. Indeed, +when the membership eventually times out, only a single RTM_DELMDB is +generated. + +Therefore, discriminate new groups from changes to existing groups by +introducing a RTM_SETMDB events to be used in the latter scenario. + +Signed-off-by: Tobias Waldekranz +--- + include/uapi/linux/rtnetlink.h | 2 ++ + net/bridge/br_mdb.c | 4 ++-- + net/bridge/br_multicast.c | 8 ++++---- + 3 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h +index 3b687d20c9ed..c459cddb1e97 100644 +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -134,6 +134,8 @@ enum { + #define RTM_DELMDB RTM_DELMDB + RTM_GETMDB = 86, + #define RTM_GETMDB RTM_GETMDB ++ RTM_SETMDB = 87, ++#define RTM_SETMDB RTM_SETMDB + + RTM_NEWNSID = 88, + #define RTM_NEWNSID RTM_NEWNSID +diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c +index 1a52a0bca086..d5757ab72d2f 100644 +--- a/net/bridge/br_mdb.c ++++ b/net/bridge/br_mdb.c +@@ -734,7 +734,7 @@ static int br_mdb_replace_group_sg(const struct br_mdb_config *cfg, + else + del_timer(&pg->timer); + +- br_mdb_notify(cfg->br->dev, mp, pg, RTM_NEWMDB); ++ br_mdb_notify(cfg->br->dev, mp, pg, RTM_SETMDB); + + return 0; + } +@@ -955,7 +955,7 @@ static int br_mdb_replace_group_star_g(const struct br_mdb_config *cfg, + else + del_timer(&pg->timer); + +- br_mdb_notify(cfg->br->dev, mp, pg, RTM_NEWMDB); ++ br_mdb_notify(cfg->br->dev, mp, pg, RTM_SETMDB); + + if (br_multicast_should_handle_mode(brmctx, cfg->group.proto)) + br_multicast_star_g_handle_mode(pg, cfg->filter_mode); +diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c +index 34be07a1fd00..9c8bf38e0079 100644 +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -619,7 +619,7 @@ static void br_multicast_fwd_src_handle(struct net_bridge_group_src *src) + sg_mp = br_mdb_ip_get(src->br, &sg_key.addr); + if (!sg_mp) + return; +- br_mdb_notify(src->br->dev, sg_mp, sg, RTM_NEWMDB); ++ br_mdb_notify(src->br->dev, sg_mp, sg, RTM_SETMDB); + } + } + +@@ -886,7 +886,7 @@ static void br_multicast_port_group_expired(struct timer_list *t) + + if (WARN_ON(!mp)) + goto out; +- br_mdb_notify(br->dev, mp, pg, RTM_NEWMDB); ++ br_mdb_notify(br->dev, mp, pg, RTM_SETMDB); + } + out: + spin_unlock(&br->multicast_lock); +@@ -2887,7 +2887,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge_mcast *brmctx, + break; + } + if (changed) +- br_mdb_notify(brmctx->br->dev, mdst, pg, RTM_NEWMDB); ++ br_mdb_notify(brmctx->br->dev, mdst, pg, RTM_SETMDB); + unlock_continue: + spin_unlock(&brmctx->br->multicast_lock); + } +@@ -3029,7 +3029,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge_mcast *brmctx, + break; + } + if (changed) +- br_mdb_notify(brmctx->br->dev, mdst, pg, RTM_NEWMDB); ++ br_mdb_notify(brmctx->br->dev, mdst, pg, RTM_SETMDB); + unlock_continue: + spin_unlock(&brmctx->br->multicast_lock); + } +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0023-nvmem-layouts-onie-tlv-Let-device-probe-even-when-TL.patch b/patches/linux/6.12.1/0023-nvmem-layouts-onie-tlv-Let-device-probe-even-when-TL.patch new file mode 100644 index 00000000..ddaa6428 --- /dev/null +++ b/patches/linux/6.12.1/0023-nvmem-layouts-onie-tlv-Let-device-probe-even-when-TL.patch @@ -0,0 +1,55 @@ +From 9a15a9276f0bc1fd10c74ebb244e615af3f60880 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Fri, 24 Nov 2023 23:29:55 +0100 +Subject: [PATCH 23/24] nvmem: layouts: onie-tlv: Let device probe even when + TLV is invalid +Organization: Addiva Elektronik + +Before this change, probing an NVMEM device, expected to contain a +valid TLV, would fail if it had not been provisioned yet. But an +obvious way of provisioning is to write the TLV to the nvmem +attribute, which would not be possible because the device would not +be successfully probed. + +Therefore, settle for reporting data corruption issues in the log, and +simply refrain from registering any cells in those cases. + +Signed-off-by: Tobias Waldekranz +--- + drivers/nvmem/layouts/onie-tlv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvmem/layouts/onie-tlv.c b/drivers/nvmem/layouts/onie-tlv.c +index 0967a32319a2..48547d5bb502 100644 +--- a/drivers/nvmem/layouts/onie-tlv.c ++++ b/drivers/nvmem/layouts/onie-tlv.c +@@ -197,7 +197,7 @@ static int onie_tlv_parse_table(struct nvmem_layout *layout) + + if (!onie_tlv_hdr_is_valid(dev, &hdr)) { + dev_err(dev, "Invalid ONIE TLV header\n"); +- return -EINVAL; ++ return 0; + } + + hdr_len = sizeof(hdr.id) + sizeof(hdr.version) + sizeof(hdr.data_len); +@@ -205,7 +205,7 @@ static int onie_tlv_parse_table(struct nvmem_layout *layout) + table_len = hdr_len + data_len; + if (table_len > ONIE_TLV_MAX_LEN) { + dev_err(dev, "Invalid ONIE TLV data length\n"); +- return -EINVAL; ++ return 0; + } + + table = devm_kmalloc(dev, table_len, GFP_KERNEL); +@@ -217,7 +217,7 @@ static int onie_tlv_parse_table(struct nvmem_layout *layout) + return ret; + + if (!onie_tlv_crc_is_valid(dev, table_len, table)) +- return -EINVAL; ++ return 0; + + data = table + hdr_len; + ret = onie_tlv_add_cells(dev, nvmem, data_len, data); +-- +2.43.0 + diff --git a/patches/linux/6.12.1/0024-usb-core-adjust-log-level-for-unauthorized-devices.patch b/patches/linux/6.12.1/0024-usb-core-adjust-log-level-for-unauthorized-devices.patch new file mode 100644 index 00000000..19e52bcd --- /dev/null +++ b/patches/linux/6.12.1/0024-usb-core-adjust-log-level-for-unauthorized-devices.patch @@ -0,0 +1,50 @@ +From 867929d898d12c8322091352cc8b59da77032e3f Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Mon, 29 Apr 2024 15:14:51 +0200 +Subject: [PATCH 24/24] usb: core: adjust log level for unauthorized devices +Organization: Addiva Elektronik + +The fact that a USB device currently is not authorized is not an error, +so let's adjust the log level so these messages slip below radar for the +commonly used 'quiet' log level. + +Signed-off-by: Joachim Wiberg +Signed-off-by: Tobias Waldekranz +--- + drivers/usb/core/driver.c | 4 ++-- + drivers/usb/core/generic.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c +index 0c3f12daac79..037f03aace9f 100644 +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -335,10 +335,10 @@ static int usb_probe_interface(struct device *dev) + return error; + + if (udev->authorized == 0) { +- dev_err(&intf->dev, "Device is not authorized for usage\n"); ++ dev_warn(&intf->dev, "Device is not authorized for usage\n"); + return error; + } else if (intf->authorized == 0) { +- dev_err(&intf->dev, "Interface %d is not authorized for usage\n", ++ dev_warn(&intf->dev, "Interface %d is not authorized for usage\n", + intf->altsetting->desc.bInterfaceNumber); + return error; + } +diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c +index b134bff5c3fe..60575a01a810 100644 +--- a/drivers/usb/core/generic.c ++++ b/drivers/usb/core/generic.c +@@ -247,7 +247,7 @@ int usb_generic_driver_probe(struct usb_device *udev) + * with the driver core and lets interface drivers bind to them. + */ + if (udev->authorized == 0) +- dev_err(&udev->dev, "Device is not authorized for usage\n"); ++ dev_warn(&udev->dev, "Device is not authorized for usage\n"); + else { + c = usb_choose_configuration(udev); + if (c >= 0) { +-- +2.43.0 + diff --git a/src/board/alder-alder/LICENSE b/src/board/alder-alder/LICENSE new file mode 100644 index 00000000..f9b6d6c1 --- /dev/null +++ b/src/board/alder-alder/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2024 The KernelKit Authors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/src/board/alder-alder/dts/Makefile b/src/board/alder-alder/dts/Makefile new file mode 100644 index 00000000..12a78a2a --- /dev/null +++ b/src/board/alder-alder/dts/Makefile @@ -0,0 +1 @@ +dtb-y += alder/alder.dtb diff --git a/board/aarch64/dts/alder/alder-mpp.h b/src/board/alder-alder/dts/alder/alder-mpp.h similarity index 100% rename from board/aarch64/dts/alder/alder-mpp.h rename to src/board/alder-alder/dts/alder/alder-mpp.h diff --git a/board/aarch64/dts/alder/alder.dts b/src/board/alder-alder/dts/alder/alder.dts similarity index 100% rename from board/aarch64/dts/alder/alder.dts rename to src/board/alder-alder/dts/alder/alder.dts diff --git a/board/aarch64/dts/alder/alder.dtsi b/src/board/alder-alder/dts/alder/alder.dtsi similarity index 100% rename from board/aarch64/dts/alder/alder.dtsi rename to src/board/alder-alder/dts/alder/alder.dtsi diff --git a/board/aarch64/dts/marvell/cn9130-patched.dtsi b/src/board/alder-alder/dts/marvell/cn9130-patched.dtsi similarity index 86% rename from board/aarch64/dts/marvell/cn9130-patched.dtsi rename to src/board/alder-alder/dts/marvell/cn9130-patched.dtsi index 8625f5cc..6ab6dd47 100644 --- a/board/aarch64/dts/marvell/cn9130-patched.dtsi +++ b/src/board/alder-alder/dts/marvell/cn9130-patched.dtsi @@ -1,4 +1,4 @@ -#include "cn9130.dtsi" +#include &cp0_syscon0 { cp0_pinctrl: pinctrl { diff --git a/src/board/marvell-cn9130-crb/LICENSE b/src/board/marvell-cn9130-crb/LICENSE new file mode 100644 index 00000000..f9b6d6c1 --- /dev/null +++ b/src/board/marvell-cn9130-crb/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2024 The KernelKit Authors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/src/board/marvell-cn9130-crb/dts/Makefile b/src/board/marvell-cn9130-crb/dts/Makefile new file mode 100644 index 00000000..2ecb28f5 --- /dev/null +++ b/src/board/marvell-cn9130-crb/dts/Makefile @@ -0,0 +1 @@ +dtb-y += marvell/cn9130-crb-A.dtb diff --git a/board/aarch64/dts/marvell/cn9130-crb-A.dts b/src/board/marvell-cn9130-crb/dts/marvell/cn9130-crb-A.dts similarity index 97% rename from board/aarch64/dts/marvell/cn9130-crb-A.dts rename to src/board/marvell-cn9130-crb/dts/marvell/cn9130-crb-A.dts index 1a60a7a0..4b1abcdc 100644 --- a/board/aarch64/dts/marvell/cn9130-crb-A.dts +++ b/src/board/marvell-cn9130-crb/dts/marvell/cn9130-crb-A.dts @@ -3,7 +3,7 @@ * Copyright (C) 2020 Marvell International Ltd. */ -#include "cn9130-crb.dtsi" +#include "arm64/marvell/cn9130-crb.dtsi" / { model = "Marvell Armada CN9130-CRB-A"; diff --git a/src/board/marvell-espressobin/LICENSE b/src/board/marvell-espressobin/LICENSE new file mode 100644 index 00000000..f9b6d6c1 --- /dev/null +++ b/src/board/marvell-espressobin/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2024 The KernelKit Authors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/src/board/marvell-espressobin/dts/Makefile b/src/board/marvell-espressobin/dts/Makefile new file mode 100644 index 00000000..c801c8db --- /dev/null +++ b/src/board/marvell-espressobin/dts/Makefile @@ -0,0 +1,5 @@ +dtb-y += marvell/armada-3720-espressobin.dtb +dtb-y += marvell/armada-3720-espressobin-emmc.dtb +dtb-y += marvell/armada-3720-espressobin-ultra.dtb +dtb-y += marvell/armada-3720-espressobin-v7.dtb +dtb-y += marvell/armada-3720-espressobin-v7-emmc.dtb diff --git a/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-emmc.dts b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-emmc.dts new file mode 100644 index 00000000..0fc22c8e --- /dev/null +++ b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-emmc.dts @@ -0,0 +1,10 @@ +#include + +/ { + chosen { + infix { + /* "admin" */ + factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A"; + }; + }; +}; diff --git a/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-ultra.dts b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-ultra.dts new file mode 100644 index 00000000..61c4b459 --- /dev/null +++ b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-ultra.dts @@ -0,0 +1,10 @@ +#include + +/ { + chosen { + infix { + /* "admin" */ + factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A"; + }; + }; +}; diff --git a/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-v7-emmc.dts b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-v7-emmc.dts new file mode 100644 index 00000000..038d96e3 --- /dev/null +++ b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-v7-emmc.dts @@ -0,0 +1,10 @@ +#include + +/ { + chosen { + infix { + /* "admin" */ + factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A"; + }; + }; +}; diff --git a/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-v7.dts b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-v7.dts new file mode 100644 index 00000000..a9009712 --- /dev/null +++ b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin-v7.dts @@ -0,0 +1,10 @@ +#include + +/ { + chosen { + infix { + /* "admin" */ + factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A"; + }; + }; +}; diff --git a/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin.dts b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin.dts new file mode 100644 index 00000000..0bd39720 --- /dev/null +++ b/src/board/marvell-espressobin/dts/marvell/armada-3720-espressobin.dts @@ -0,0 +1,10 @@ +#include + +/ { + chosen { + infix { + /* "admin" */ + factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A"; + }; + }; +}; diff --git a/src/board/microchip-sparx5-pcb135/LICENSE b/src/board/microchip-sparx5-pcb135/LICENSE new file mode 100644 index 00000000..f9b6d6c1 --- /dev/null +++ b/src/board/microchip-sparx5-pcb135/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2024 The KernelKit Authors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/src/board/microchip-sparx5-pcb135/dts/Makefile b/src/board/microchip-sparx5-pcb135/dts/Makefile new file mode 100644 index 00000000..1c56e4d0 --- /dev/null +++ b/src/board/microchip-sparx5-pcb135/dts/Makefile @@ -0,0 +1 @@ +dtb-y += microchip/sparx5_pcb135_emmc_no_psci.dtb diff --git a/board/aarch64/dts/microchip/sparx5_pcb135_emmc_no_psci.dts b/src/board/microchip-sparx5-pcb135/dts/microchip/sparx5_pcb135_emmc_no_psci.dts similarity index 89% rename from board/aarch64/dts/microchip/sparx5_pcb135_emmc_no_psci.dts rename to src/board/microchip-sparx5-pcb135/dts/microchip/sparx5_pcb135_emmc_no_psci.dts index 4b5b2b06..aeede774 100644 --- a/board/aarch64/dts/microchip/sparx5_pcb135_emmc_no_psci.dts +++ b/src/board/microchip-sparx5-pcb135/dts/microchip/sparx5_pcb135_emmc_no_psci.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include "sparx5_pcb135_emmc.dts" +#include &cpu0 { enable-method = "spin-table"; diff --git a/src/board/styx-dcp-sc-28p/LICENSE b/src/board/styx-dcp-sc-28p/LICENSE new file mode 100644 index 00000000..f9b6d6c1 --- /dev/null +++ b/src/board/styx-dcp-sc-28p/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2024 The KernelKit Authors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/src/board/styx-dcp-sc-28p/dts/Makefile b/src/board/styx-dcp-sc-28p/dts/Makefile new file mode 100644 index 00000000..7c07ccff --- /dev/null +++ b/src/board/styx-dcp-sc-28p/dts/Makefile @@ -0,0 +1,2 @@ +dtb-y += styx/dcp-sc-28p-a.dtb +dtb-y += styx/dcp-sc-28p-b.dtb diff --git a/src/board/styx-dcp-sc-28p/dts/marvell/cn9130-patched.dtsi b/src/board/styx-dcp-sc-28p/dts/marvell/cn9130-patched.dtsi new file mode 100644 index 00000000..6ab6dd47 --- /dev/null +++ b/src/board/styx-dcp-sc-28p/dts/marvell/cn9130-patched.dtsi @@ -0,0 +1,12 @@ +#include + +&cp0_syscon0 { + cp0_pinctrl: pinctrl { + /* For some reason, this is missing from cn9130.dtsi */ + compatible = "marvell,cp115-standalone-pinctrl"; + }; +}; + +&cp0_xmdio { + clock-names = "gop_clk", "mg_clk", "mg_core_clk", "axi_clk"; +}; diff --git a/board/aarch64/dts/styx/dcp-sc-28p-a.dts b/src/board/styx-dcp-sc-28p/dts/styx/dcp-sc-28p-a.dts similarity index 100% rename from board/aarch64/dts/styx/dcp-sc-28p-a.dts rename to src/board/styx-dcp-sc-28p/dts/styx/dcp-sc-28p-a.dts diff --git a/board/aarch64/dts/styx/dcp-sc-28p-b.dts b/src/board/styx-dcp-sc-28p/dts/styx/dcp-sc-28p-b.dts similarity index 100% rename from board/aarch64/dts/styx/dcp-sc-28p-b.dts rename to src/board/styx-dcp-sc-28p/dts/styx/dcp-sc-28p-b.dts diff --git a/board/aarch64/dts/styx/dcp-sc-28p-mpp.h b/src/board/styx-dcp-sc-28p/dts/styx/dcp-sc-28p-mpp.h similarity index 100% rename from board/aarch64/dts/styx/dcp-sc-28p-mpp.h rename to src/board/styx-dcp-sc-28p/dts/styx/dcp-sc-28p-mpp.h diff --git a/board/aarch64/dts/styx/dcp-sc-28p.dtsi b/src/board/styx-dcp-sc-28p/dts/styx/dcp-sc-28p.dtsi similarity index 100% rename from board/aarch64/dts/styx/dcp-sc-28p.dtsi rename to src/board/styx-dcp-sc-28p/dts/styx/dcp-sc-28p.dtsi diff --git a/board/aarch64/rootfs/boot/styx/styx-b.dtb b/src/board/styx-dcp-sc-28p/rootfs/boot/styx/styx-b.dtb similarity index 100% rename from board/aarch64/rootfs/boot/styx/styx-b.dtb rename to src/board/styx-dcp-sc-28p/rootfs/boot/styx/styx-b.dtb diff --git a/board/aarch64/rootfs/boot/styx/styx.dtb b/src/board/styx-dcp-sc-28p/rootfs/boot/styx/styx.dtb similarity index 100% rename from board/aarch64/rootfs/boot/styx/styx.dtb rename to src/board/styx-dcp-sc-28p/rootfs/boot/styx/styx.dtb diff --git a/board/aarch64/rootfs/usr/libexec/styx/led.sh b/src/board/styx-dcp-sc-28p/rootfs/usr/libexec/styx/led.sh similarity index 100% rename from board/aarch64/rootfs/usr/libexec/styx/led.sh rename to src/board/styx-dcp-sc-28p/rootfs/usr/libexec/styx/led.sh diff --git a/board/aarch64/rootfs/usr/share/product/dcp-sc-28p/etc/finit.d/available/iitod.conf b/src/board/styx-dcp-sc-28p/rootfs/usr/share/product/dcp-sc-28p/etc/finit.d/available/iitod.conf similarity index 100% rename from board/aarch64/rootfs/usr/share/product/dcp-sc-28p/etc/finit.d/available/iitod.conf rename to src/board/styx-dcp-sc-28p/rootfs/usr/share/product/dcp-sc-28p/etc/finit.d/available/iitod.conf diff --git a/board/aarch64/rootfs/usr/share/product/styx,dcp-sc-28p/etc/product/init.d/S10-led b/src/board/styx-dcp-sc-28p/rootfs/usr/share/product/styx,dcp-sc-28p/etc/product/init.d/S10-led similarity index 100% rename from board/aarch64/rootfs/usr/share/product/styx,dcp-sc-28p/etc/product/init.d/S10-led rename to src/board/styx-dcp-sc-28p/rootfs/usr/share/product/styx,dcp-sc-28p/etc/product/init.d/S10-led diff --git a/utils/kernel-refresh.sh b/utils/kernel-refresh.sh index 760fc69e..74f9cad5 100755 --- a/utils/kernel-refresh.sh +++ b/utils/kernel-refresh.sh @@ -60,6 +60,9 @@ if ! [ "$PDIR" ]; then exit 1 fi -git -C $PDIR rm *.patch +KDIR=$(readlink -f $KDIR) +PDIR=$(readlink -f $PDIR) + +git ls-files --error-unmatch $PDIR 1>/dev/null 2>&1 && git -C $PDIR rm *.patch git -C $KDIR format-patch -o $PDIR $KTAG..HEAD git -C $PDIR add *.patch