mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-02 13:53:01 +02:00
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
config BR2_PACKAGE_ALDER_ALDER
|
||||
bool "Alder"
|
||||
depends on BR2_aarch64
|
||||
help
|
||||
Alder
|
||||
@@ -0,0 +1,2 @@
|
||||
$(eval $(ix-board))
|
||||
$(eval $(generic-package))
|
||||
@@ -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))
|
||||
@@ -0,0 +1,9 @@
|
||||
include Makefile
|
||||
|
||||
install: $(addprefix $(DESTDIR)/boot/,$(dtb-y))
|
||||
|
||||
$(DESTDIR)/boot/%.dtb: %.dtb
|
||||
@echo " DTB-INSTALL $<"
|
||||
@install -D $< $@
|
||||
|
||||
.PHONY: install
|
||||
@@ -0,0 +1,5 @@
|
||||
config BR2_PACKAGE_MARVELL_CN9130_CRB
|
||||
bool "Marvell CN9130-CRB"
|
||||
depends on BR2_aarch64
|
||||
help
|
||||
Customer Reference Board for CN9130
|
||||
@@ -0,0 +1,2 @@
|
||||
$(eval $(ix-board))
|
||||
$(eval $(generic-package))
|
||||
@@ -0,0 +1,5 @@
|
||||
config BR2_PACKAGE_MARVELL_ESPRESSOBIN
|
||||
bool "Marvell ESPRESSObin"
|
||||
depends on BR2_aarch64
|
||||
help
|
||||
Marvell ESPRESSObin
|
||||
@@ -0,0 +1,2 @@
|
||||
$(eval $(ix-board))
|
||||
$(eval $(generic-package))
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
$(eval $(ix-board))
|
||||
$(eval $(generic-package))
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
$(eval $(ix-board))
|
||||
$(eval $(generic-package))
|
||||
@@ -0,0 +1,32 @@
|
||||
From f5f25417c0e65f45c6a254e5a1f00c4fd5919058 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
From fc68336f274aac22426b271c4d4a7ef0bfc76006 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
From 66e1fc9ab54680989c02dab907743133674a07cf Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
From 7c9d33f9176e5d2173646aee7b15176e40fabbb0 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
From 408a1681d4bbb44ede8d7d738f96a2fc27deb813 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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 <net/dsa.h>
|
||||
+
|
||||
+#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
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
From 9bfe65e40336c449720f96230ccc22c831045e9d Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
From 0f009562d467672b7f5ff9366ad4ec9df9044137 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
From 027a5fcd4da6cf02ff8d2f6dc5ff1202f81db8ca Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
From ef232a32e69a5edb1a62067d4871fb70e8c3ddd7 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
From 48338a7ca5f0a7be3b16acd1762ec0b73088ac4c Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
From 2c3ceab75d2ebb36326a5bc09b17d9409a11d2fa Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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 <linux/gpio/consumer.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <net/dsa.h>
|
||||
+#include <net/pkt_sched.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
From b1f2d857a7457c8c965d281d8c8875ad491670a7 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
From eedb27bcce73ed62534528bd098b897954f98d3c Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
From f84d14369aad6ad2d2aec71dcf907d2ff70aa4fa Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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 <linux/bitfield.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/delay.h>
|
||||
+#include <linux/firmware.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/marvell_phy.h>
|
||||
#include <linux/phy.h>
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
From 0ffa9ba9b48fbd9f818b8c789202ae85bc401f47 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,517 @@
|
||||
From 2c99fab374153c7eac6ba9874d47367871cec640 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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 <linux/firmware.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/marvell_phy.h>
|
||||
+#include <linux/of.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/sfp.h>
|
||||
#include <linux/netdevice.h>
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
From 6dd8ed1ea83d55469e20b9c13b41810fc2e29af4 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
From 17cfde24d88c30c303659f2d8f488c2717592422 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
From c75c32e677f22caf857981d1c8a3f580bf367230 Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Wiberg <troglobit@gmail.com>
|
||||
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 <troglobit@gmail.com>
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
From d8c84564a7ef2a5faf4caf76ed797131967258bb Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Wiberg <troglobit@gmail.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
From bc2cbf4dd3c5a756e949f6abe7ffc7fe16e499d6 Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Wiberg <troglobit@gmail.com>
|
||||
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 <troglobit@gmail.com>
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
From 65bf34b0195259808333b8fa7b53b8f588c58f32 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
From 9a15a9276f0bc1fd10c74ebb244e615af3f60880 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
From 867929d898d12c8322091352cc8b59da77032e3f Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Wiberg <troglobit@gmail.com>
|
||||
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 <troglobit@gmail.com>
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
@@ -0,0 +1 @@
|
||||
dtb-y += alder/alder.dtb
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#include "cn9130.dtsi"
|
||||
#include <arm64/marvell/cn9130.dtsi>
|
||||
|
||||
&cp0_syscon0 {
|
||||
cp0_pinctrl: pinctrl {
|
||||
@@ -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.
|
||||
@@ -0,0 +1 @@
|
||||
dtb-y += marvell/cn9130-crb-A.dtb
|
||||
+1
-1
@@ -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";
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <arm64/marvell/armada-3720-espressobin-emmc.dts>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
infix {
|
||||
/* "admin" */
|
||||
factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <arm64/marvell/armada-3720-espressobin-ultra.dts>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
infix {
|
||||
/* "admin" */
|
||||
factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <arm64/marvell/armada-3720-espressobin-v7-emmc.dts>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
infix {
|
||||
/* "admin" */
|
||||
factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <arm64/marvell/armada-3720-espressobin-v7.dts>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
infix {
|
||||
/* "admin" */
|
||||
factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <arm64/marvell/armada-3720-espressobin.dts>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
infix {
|
||||
/* "admin" */
|
||||
factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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.
|
||||
@@ -0,0 +1 @@
|
||||
dtb-y += microchip/sparx5_pcb135_emmc_no_psci.dtb
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
#include "sparx5_pcb135_emmc.dts"
|
||||
#include <arm64/microchip/sparx5_pcb135_emmc.dts>
|
||||
|
||||
&cpu0 {
|
||||
enable-method = "spin-table";
|
||||
@@ -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.
|
||||
@@ -0,0 +1,2 @@
|
||||
dtb-y += styx/dcp-sc-28p-a.dtb
|
||||
dtb-y += styx/dcp-sc-28p-b.dtb
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <arm64/marvell/cn9130.dtsi>
|
||||
|
||||
&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";
|
||||
};
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user