Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
@@ -83,6 +83,15 @@ menu "Global build settings"
|
||||
--allow-untrusted when installing self-compiled packages to a
|
||||
firmware compiled by the same buildhost as public key matches.
|
||||
|
||||
config SIGN_FIRMWARE
|
||||
bool "Cryptographically sign firmware images"
|
||||
default n if BUILDBOT
|
||||
default y
|
||||
help
|
||||
Append a signature to firmware images so that sysupgrade can verify
|
||||
their authenticity before flashing. OpenWrt's build infrastructure
|
||||
signs images with temporary keys; disabling this drops the signature.
|
||||
|
||||
comment "General build options"
|
||||
|
||||
config TESTING_KERNEL
|
||||
|
||||
@@ -91,12 +91,12 @@ metadata_json = \
|
||||
define Build/append-metadata
|
||||
$(if $(SUPPORTED_DEVICES),-echo $(call metadata_json) | fwtool -I - $@)
|
||||
sha256sum "$@" | cut -d" " -f1 > "$@.sha256sum"
|
||||
[ ! -s "$(BUILD_KEY)" -o ! -s "$(BUILD_KEY).ucert" -o ! -s "$@" ] || { \
|
||||
$(if $(CONFIG_SIGN_FIRMWARE),[ ! -s "$(BUILD_KEY)" -o ! -s "$(BUILD_KEY).ucert" -o ! -s "$@" ] || { \
|
||||
cp "$(BUILD_KEY).ucert" "$@.ucert" ;\
|
||||
usign -S -m "$@" -s "$(BUILD_KEY)" -x "$@.sig" ;\
|
||||
ucert -A -c "$@.ucert" -x "$@.sig" ;\
|
||||
fwtool -S "$@.ucert" "$@" ;\
|
||||
}
|
||||
})
|
||||
endef
|
||||
|
||||
metadata_gl_json = \
|
||||
@@ -122,12 +122,12 @@ metadata_gl_json = \
|
||||
define Build/append-gl-metadata
|
||||
$(if $(SUPPORTED_DEVICES),-echo $(call metadata_gl_json,$(SUPPORTED_DEVICES)) | fwtool -I - $@)
|
||||
sha256sum "$@" | cut -d" " -f1 > "$@.sha256sum"
|
||||
[ ! -s "$(BUILD_KEY)" -o ! -s "$(BUILD_KEY).ucert" -o ! -s "$@" ] || { \
|
||||
$(if $(CONFIG_SIGN_FIRMWARE),[ ! -s "$(BUILD_KEY)" -o ! -s "$(BUILD_KEY).ucert" -o ! -s "$@" ] || { \
|
||||
cp "$(BUILD_KEY).ucert" "$@.ucert" ;\
|
||||
usign -S -m "$@" -s "$(BUILD_KEY)" -x "$@.sig" ;\
|
||||
ucert -A -c "$@.ucert" -x "$@.sig" ;\
|
||||
fwtool -S "$@.ucert" "$@" ;\
|
||||
}
|
||||
})
|
||||
endef
|
||||
|
||||
define Build/append-teltonika-metadata
|
||||
|
||||
@@ -102,6 +102,7 @@ KERNEL_MAKE = $(MAKE) $(KERNEL_MAKEOPTS)
|
||||
|
||||
KERNEL_MAKE_FLAGS = \
|
||||
KCFLAGS="$(call iremap,$(BUILD_DIR),$(notdir $(BUILD_DIR))) $(filter-out -fno-plt,$(call qstrip,$(CONFIG_EXTRA_OPTIMIZATION))) $(call qstrip,$(CONFIG_KERNEL_CFLAGS))" \
|
||||
KAFLAGS="$(call iremap,$(BUILD_DIR),$(notdir $(BUILD_DIR)))" \
|
||||
HOSTCFLAGS="$(HOST_CFLAGS) -Wall -Wmissing-prototypes -Wstrict-prototypes" \
|
||||
CROSS_COMPILE="$(KERNEL_CROSS)" \
|
||||
ARCH="$(LINUX_KARCH)" \
|
||||
@@ -121,6 +122,10 @@ ifneq (,$(KERNEL_CC))
|
||||
KERNEL_MAKE_FLAGS += CC="$(KERNEL_CC)"
|
||||
endif
|
||||
|
||||
ifeq ($(HOST_OS),Darwin)
|
||||
KERNEL_MAKE_FLAGS += MACOSX_DEPLOYMENT_TARGET="$(shell sw_vers -productVersion)"
|
||||
endif
|
||||
|
||||
KERNEL_NOSTDINC_FLAGS = \
|
||||
-nostdinc $(if $(DUMP),, -isystem $(shell $(TARGET_CC) -print-file-name=include))
|
||||
|
||||
|
||||
+1
-1
@@ -278,7 +278,7 @@ index 00000000000..e1fda15ba37
|
||||
+ reg = <0x0 0x1fbf0200 0x0 0xc0>;
|
||||
+
|
||||
+ an7583_pinctrl: pinctrl {
|
||||
+ compatible = "airoha,en7583-pinctrl";
|
||||
+ compatible = "airoha,an7583-pinctrl";
|
||||
+
|
||||
+ interrupt-parent = <&gic>;
|
||||
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright (C) 2025 OpenWrt.org
|
||||
#
|
||||
|
||||
[ -e /etc/config/ubootenv ] && exit 0
|
||||
|
||||
touch /etc/config/ubootenv
|
||||
|
||||
. /lib/uboot-envtools.sh
|
||||
. /lib/functions.sh
|
||||
|
||||
board=$(board_name)
|
||||
|
||||
case "$board" in
|
||||
nokia,xg-040g-mf)
|
||||
ubootenv_add_mtd "u-boot-env" "0x1c000" "0x4000" "0x4000"
|
||||
;;
|
||||
esac
|
||||
|
||||
config_load ubootenv
|
||||
config_foreach ubootenv_add_app_config
|
||||
|
||||
exit 0
|
||||
@@ -32,6 +32,7 @@ allnet,all0256n-4m|\
|
||||
allnet,all0256n-8m|\
|
||||
allnet,all5002|\
|
||||
asiarf,ap7621-004-v3|\
|
||||
comfast,cf-ew84|\
|
||||
huasifei,shf283|\
|
||||
jdcloud,re-cp-02|\
|
||||
plasmacloud,pax1800-lite|\
|
||||
|
||||
@@ -21,6 +21,7 @@ zyxel,gs1900-8-a1|\
|
||||
zyxel,gs1900-8hp-a1|\
|
||||
zyxel,gs1900-8hp-b1|\
|
||||
zyxel,gs1900-10hp-a1|\
|
||||
zyxel,gs1900-10hp-b1|\
|
||||
zyxel,gs1900-16-a1|\
|
||||
zyxel,gs1900-24-a1|\
|
||||
zyxel,gs1900-24e-a1|\
|
||||
|
||||
@@ -33,13 +33,11 @@ endef
|
||||
define Package/rtl826x-firmware
|
||||
$(call Package/rtl826x-firmware/Default)
|
||||
TITLE:=Realtek RTL8251L/RTL8261BE/RTL8261N/RTL8254B/RTL8264/RTL8264B firmware
|
||||
VERSION:=20221115
|
||||
endef
|
||||
|
||||
define Package/rtl826x-lp-firmware
|
||||
$(call Package/rtl826x-firmware/Default)
|
||||
TITLE:=Realtek RTL8251L/RTL8261BE/RTL8261N/RTL8254B/RTL8264/RTL8264B low-power firmware
|
||||
VERSION:=20240729
|
||||
PROVIDES:=rtl826x-firmware
|
||||
CONFLICTS:=rtl826x-firmware
|
||||
endef
|
||||
|
||||
@@ -770,101 +770,6 @@ endef
|
||||
$(eval $(call KernelPackage,crypto-michael-mic))
|
||||
|
||||
|
||||
define KernelPackage/crypto-misc
|
||||
TITLE:=Other CryptoAPI modules
|
||||
DEPENDS:=+kmod-crypto-xts +kmod-crypto-user
|
||||
KCONFIG:= \
|
||||
CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y \
|
||||
CONFIG_CRYPTO_CAMELLIA_X86_64 \
|
||||
CONFIG_CRYPTO_BLOWFISH_X86_64 \
|
||||
CONFIG_CRYPTO_TWOFISH_X86_64 \
|
||||
CONFIG_CRYPTO_TWOFISH_X86_64_3WAY \
|
||||
CONFIG_CRYPTO_SERPENT_SSE2_X86_64 \
|
||||
CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 \
|
||||
CONFIG_CRYPTO_CAST5_AVX_X86_64 \
|
||||
CONFIG_CRYPTO_CAST6_AVX_X86_64 \
|
||||
CONFIG_CRYPTO_TWOFISH_AVX_X86_64 \
|
||||
CONFIG_CRYPTO_SERPENT_AVX_X86_64 \
|
||||
CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 \
|
||||
CONFIG_CRYPTO_SERPENT_AVX2_X86_64 \
|
||||
CONFIG_CRYPTO_SERPENT_SSE2_586 \
|
||||
CONFIG_CRYPTO_ANUBIS \
|
||||
CONFIG_CRYPTO_BLOWFISH \
|
||||
CONFIG_CRYPTO_CAMELLIA \
|
||||
CONFIG_CRYPTO_CAST5 \
|
||||
CONFIG_CRYPTO_CAST6 \
|
||||
CONFIG_CRYPTO_KHAZAD \
|
||||
CONFIG_CRYPTO_SERPENT \
|
||||
CONFIG_CRYPTO_TEA \
|
||||
CONFIG_CRYPTO_TWOFISH \
|
||||
CONFIG_CRYPTO_TWOFISH_COMMON \
|
||||
CONFIG_CRYPTO_TWOFISH_586 \
|
||||
CONFIG_CRYPTO_WP512
|
||||
FILES:= \
|
||||
$(LINUX_DIR)/crypto/anubis.ko \
|
||||
$(LINUX_DIR)/crypto/camellia_generic.ko \
|
||||
$(LINUX_DIR)/crypto/cast_common.ko \
|
||||
$(LINUX_DIR)/crypto/cast5_generic.ko \
|
||||
$(LINUX_DIR)/crypto/cast6_generic.ko \
|
||||
$(LINUX_DIR)/crypto/khazad.ko \
|
||||
$(LINUX_DIR)/crypto/tea.ko \
|
||||
$(LINUX_DIR)/crypto/twofish_common.ko \
|
||||
$(LINUX_DIR)/crypto/wp512.ko \
|
||||
$(LINUX_DIR)/crypto/twofish_generic.ko \
|
||||
$(LINUX_DIR)/crypto/blowfish_common.ko \
|
||||
$(LINUX_DIR)/crypto/blowfish_generic.ko \
|
||||
$(LINUX_DIR)/crypto/serpent_generic.ko
|
||||
AUTOLOAD:=$(call AutoLoad,10,anubis camellia_generic cast_common \
|
||||
cast5_generic cast6_generic khazad tea twofish_common \
|
||||
wp512 blowfish_common serpent_generic)
|
||||
ifndef CONFIG_TARGET_x86
|
||||
AUTOLOAD+= $(call AutoLoad,10,twofish_generic blowfish_generic)
|
||||
endif
|
||||
$(call AddDepends/crypto)
|
||||
endef
|
||||
|
||||
ifndef CONFIG_TARGET_x86_64
|
||||
define KernelPackage/crypto-misc/x86
|
||||
FILES+= \
|
||||
$(LINUX_DIR)/arch/x86/crypto/twofish-i586.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/serpent-sse2-i586.ko \
|
||||
$(LINUX_DIR)/crypto/cryptd.ko@lt6.18 \
|
||||
$(LINUX_DIR)/crypto/crypto_simd.ko@lt6.18
|
||||
AUTOLOAD+= $(call AutoLoad,10,cryptd@lt6.18 \
|
||||
serpent-sse2-i586 twofish-i586 blowfish_generic)
|
||||
endef
|
||||
endif
|
||||
|
||||
ifndef CONFIG_TARGET_uml
|
||||
define KernelPackage/crypto-misc/x86_64
|
||||
FILES+= \
|
||||
$(LINUX_DIR)/arch/x86/crypto/camellia-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/blowfish-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/twofish-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/twofish-x86_64-3way.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/serpent-sse2-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/camellia-aesni-avx-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/cast5-avx-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/cast6-avx-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/twofish-avx-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/serpent-avx-x86_64.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/camellia-aesni-avx2.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/serpent-avx2.ko
|
||||
AUTOLOAD+= $(call AutoLoad,10,camellia-x86_64 \
|
||||
camellia-aesni-avx-x86_64 camellia-aesni-avx2 cast5-avx-x86_64 \
|
||||
cast6-avx-x86_64 twofish-x86_64 twofish-x86_64-3way \
|
||||
twofish-avx-x86_64 blowfish-x86_64 serpent-avx-x86_64 serpent-avx2)
|
||||
endef
|
||||
endif
|
||||
|
||||
ifdef KernelPackage/crypto-misc/$(ARCH)
|
||||
KernelPackage/crypto-misc/$(CRYPTO_TARGET)=\
|
||||
$(KernelPackage/crypto-misc/$(ARCH))
|
||||
endif
|
||||
|
||||
$(eval $(call KernelPackage,crypto-misc))
|
||||
|
||||
|
||||
define KernelPackage/crypto-null
|
||||
TITLE:=Null CryptoAPI module
|
||||
KCONFIG:=CONFIG_CRYPTO_NULL
|
||||
|
||||
@@ -1418,7 +1418,7 @@ define KernelPackage/e1000
|
||||
CONFIG_E1000_DISABLE_PACKET_SPLIT=n \
|
||||
CONFIG_E1000_NAPI=y
|
||||
FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/e1000/e1000.ko
|
||||
AUTOLOAD:=$(call AutoLoad,35,e1000)
|
||||
AUTOLOAD:=$(call AutoLoad,35,e1000,1)
|
||||
endef
|
||||
|
||||
define KernelPackage/e1000/description
|
||||
@@ -1872,7 +1872,7 @@ define KernelPackage/vmxnet3
|
||||
DEPENDS:=@PCI_SUPPORT
|
||||
KCONFIG:=CONFIG_VMXNET3
|
||||
FILES:=$(LINUX_DIR)/drivers/net/vmxnet3/vmxnet3.ko
|
||||
AUTOLOAD:=$(call AutoLoad,35,vmxnet3)
|
||||
AUTOLOAD:=$(call AutoLoad,35,vmxnet3,1)
|
||||
endef
|
||||
|
||||
define KernelPackage/vmxnet3/description
|
||||
|
||||
@@ -935,6 +935,93 @@ endef
|
||||
$(eval $(call KernelPackage,echo))
|
||||
|
||||
|
||||
define KernelPackage/tee
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=Trusted Execution Environment (TEE) support
|
||||
DEPENDS:=+kmod-dma-buf
|
||||
KCONFIG:=CONFIG_TEE
|
||||
FILES:=$(LINUX_DIR)/drivers/tee/tee.ko
|
||||
AUTOLOAD:=$(call AutoLoad,20,tee,1)
|
||||
endef
|
||||
|
||||
define KernelPackage/tee/description
|
||||
Generic Trusted Execution Environment subsystem, the interface used to
|
||||
communicate with a trusted OS running in a secure environment.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,tee))
|
||||
|
||||
|
||||
define KernelPackage/optee
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=OP-TEE driver
|
||||
DEPENDS:=+kmod-i2c-core +kmod-tee
|
||||
KCONFIG:= \
|
||||
CONFIG_OPTEE \
|
||||
CONFIG_OPTEE_INSECURE_LOAD_IMAGE=n
|
||||
FILES:=$(LINUX_DIR)/drivers/tee/optee/optee.ko
|
||||
AUTOLOAD:=$(call AutoLoad,21,optee,1)
|
||||
endef
|
||||
|
||||
define KernelPackage/optee/description
|
||||
Driver for OP-TEE, the Open Portable Trusted Execution Environment running
|
||||
in the Arm secure world, reached over the SMCCC or FF-A transport.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,optee))
|
||||
|
||||
|
||||
define KernelPackage/optee-rng
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=OP-TEE based Random Number Generator
|
||||
DEPENDS:=+kmod-optee +kmod-random-core
|
||||
KCONFIG:=CONFIG_HW_RANDOM_OPTEE
|
||||
FILES:=$(LINUX_DIR)/drivers/char/hw_random/optee-rng.ko
|
||||
AUTOLOAD:=$(call AutoLoad,22,optee-rng,1)
|
||||
endef
|
||||
|
||||
define KernelPackage/optee-rng/description
|
||||
Exposes the random number generator provided by OP-TEE through the kernel
|
||||
hwrng interface.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,optee-rng))
|
||||
|
||||
|
||||
define KernelPackage/scmi-transport-optee
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=SCMI transport based on OP-TEE service
|
||||
DEPENDS:=@(TARGET_rockchip||TARGET_stm32) +kmod-optee
|
||||
KCONFIG:=CONFIG_ARM_SCMI_TRANSPORT_OPTEE
|
||||
FILES:=$(LINUX_DIR)/drivers/firmware/arm_scmi/transports/scmi_transport_optee.ko
|
||||
AUTOLOAD:=$(call AutoProbe,scmi_transport_optee)
|
||||
endef
|
||||
|
||||
define KernelPackage/scmi-transport-optee/description
|
||||
Arm SCMI transport using an OP-TEE service to communicate with the
|
||||
platform firmware implementing the SCMI server.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,scmi-transport-optee))
|
||||
|
||||
|
||||
define KernelPackage/tee-stmm-efi
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=TEE based EFI runtime variable service
|
||||
DEPENDS:=@TARGET_armsr +kmod-optee
|
||||
KCONFIG:=CONFIG_TEE_STMM_EFI
|
||||
FILES:=$(LINUX_DIR)/drivers/firmware/efi/stmm/tee_stmm_efi.ko
|
||||
AUTOLOAD:=$(call AutoProbe,tee_stmm_efi)
|
||||
endef
|
||||
|
||||
define KernelPackage/tee-stmm-efi/description
|
||||
Provides EFI runtime variable services through the StandAloneMM Trusted
|
||||
Application running in OP-TEE.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,tee-stmm-efi))
|
||||
|
||||
|
||||
define KernelPackage/keys-encrypted
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=encrypted keys on kernel keyring
|
||||
@@ -991,6 +1078,23 @@ endef
|
||||
|
||||
$(eval $(call KernelPackage,tpm))
|
||||
|
||||
define KernelPackage/tpm-ftpm-tee
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=TEE based firmware TPM (fTPM)
|
||||
DEPENDS:=+kmod-tpm +kmod-optee
|
||||
KCONFIG:=CONFIG_TCG_FTPM_TEE
|
||||
FILES:=$(LINUX_DIR)/drivers/char/tpm/tpm_ftpm_tee.ko
|
||||
AUTOLOAD:=$(call AutoLoad,30,tpm_ftpm_tee,1)
|
||||
endef
|
||||
|
||||
define KernelPackage/tpm-ftpm-tee/description
|
||||
Driver for a firmware TPM (fTPM) running as a Trusted Application inside a
|
||||
TEE such as OP-TEE. It presents the fTPM to Linux as a TPM 2.0 device,
|
||||
bound over the TEE client bus or a microsoft,ftpm device tree node.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,tpm-ftpm-tee))
|
||||
|
||||
define KernelPackage/tpm-tis
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=TPM TIS 1.2 Interface / TPM 2.0 FIFO Interface
|
||||
|
||||
@@ -143,3 +143,21 @@ define KernelPackage/pse-realtek-mcu-uart/description
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,pse-realtek-mcu-uart))
|
||||
|
||||
define KernelPackage/pse-hasivo-hs104
|
||||
SUBMENU:=$(PSE_MENU)
|
||||
TITLE:=Hasivo HS104 PSE controller support
|
||||
KCONFIG:=CONFIG_PSE_HASIVO_HS104
|
||||
DEPENDS:=+kmod-i2c-core
|
||||
FILES:=$(LINUX_DIR)/drivers/net/pse-pd/hasivo_hs104.ko
|
||||
AUTOLOAD:=$(call AutoProbe,hasivo_hs104)
|
||||
$(call AddDepends/pse-pd)
|
||||
endef
|
||||
|
||||
define KernelPackage/pse-hasivo-hs104/description
|
||||
Kernel module for the Hasivo HS104 PoE PSE controller chips.
|
||||
Supports the HS104PTI/HS104PBI single-chip PoE PSE controllers
|
||||
managing 4 delivery channels for 802.3af/at/bt power over I2C.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,pse-hasivo-hs104))
|
||||
|
||||
@@ -134,6 +134,25 @@ endef
|
||||
$(eval $(call KernelPackage,rtc-mv))
|
||||
|
||||
|
||||
define KernelPackage/rtc-optee
|
||||
SUBMENU:=$(RTC_MENU)
|
||||
TITLE:=OP-TEE based RTC support
|
||||
DEFAULT:=m if ALL_KMODS && RTC_SUPPORT
|
||||
DEPENDS:=+kmod-optee
|
||||
KCONFIG:=CONFIG_RTC_DRV_OPTEE \
|
||||
CONFIG_RTC_CLASS=y
|
||||
FILES:=$(LINUX_DIR)/drivers/rtc/rtc-optee.ko
|
||||
AUTOLOAD:=$(call AutoProbe,rtc-optee)
|
||||
endef
|
||||
|
||||
define KernelPackage/rtc-optee/description
|
||||
Kernel module for the RTC service exposed by the OP-TEE Trusted
|
||||
Execution Environment.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,rtc-optee))
|
||||
|
||||
|
||||
define KernelPackage/rtc-pcf8563
|
||||
SUBMENU:=$(RTC_MENU)
|
||||
TITLE:=Philips PCF8563/Epson RTC8564 RTC support
|
||||
|
||||
@@ -70,9 +70,9 @@ function setup_phy(phy, config, data) {
|
||||
config.channel = +config.channel;
|
||||
config.frequency = get_channel_frequency(config.band, config.channel);
|
||||
|
||||
if (config.country) {
|
||||
log(`Setting country code to ${config.country}`);
|
||||
system(`iw reg set ${config.country}`);
|
||||
if (config.country_code) {
|
||||
log(`Setting country code to ${config.country_code}`);
|
||||
system(`iw reg set ${config.country_code}`);
|
||||
}
|
||||
|
||||
set_default(config, 'rxantenna', 0xffffffff);
|
||||
@@ -256,6 +256,7 @@ function setup() {
|
||||
// fallthrough
|
||||
case 'sta':
|
||||
data.ap_start_disabled = true;
|
||||
data.channel_follow = true;
|
||||
let config = supplicant.generate(supplicant_data, data, v);
|
||||
if (mode == "mesh")
|
||||
config_add_mesh_params(config, v.config);
|
||||
|
||||
@@ -4,11 +4,11 @@ import * as libuci from 'uci';
|
||||
import { md5 } from 'digest';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { append, append_raw, append_value, append_vars, append_string_vars, comment, push_config, set_default, touch_file } from 'wifi.common';
|
||||
import { append, append_raw, append_value, append_vars, append_list, append_string_vars, comment, push_config, set_default, touch_file } from 'wifi.common';
|
||||
import * as netifd from 'wifi.netifd';
|
||||
import * as iface from 'wifi.iface';
|
||||
|
||||
function iface_setup(config) {
|
||||
function iface_setup(config, phy, num_global_macaddr, macaddr_base) {
|
||||
switch(config.fixup) {
|
||||
case 'owe':
|
||||
config.ignore_broadcast_ssid = true;
|
||||
@@ -22,7 +22,11 @@ function iface_setup(config) {
|
||||
config.owe_transition_ssid = config.ssid + 'OWE';
|
||||
config.encryption = 'none';
|
||||
config.ignore_broadcast_ssid = false;
|
||||
iface.prepare(config);
|
||||
/* the transition BSS needs its own address, not the main BSS's */
|
||||
config.macaddr = null;
|
||||
delete config.default_macaddr;
|
||||
delete config.random_macaddr;
|
||||
iface.prepare(config, phy, num_global_macaddr, macaddr_base);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -51,6 +55,10 @@ function iface_setup(config) {
|
||||
config.wmm_enabled = 1;
|
||||
append_string_vars(config, [ 'ssid2' ]);
|
||||
|
||||
/* vendor_elements is a single concatenated hex blob, not one per line */
|
||||
if (type(config.vendor_elements) == 'array')
|
||||
config.vendor_elements = join('', config.vendor_elements);
|
||||
|
||||
append_vars(config, [
|
||||
'ctrl_interface', 'ap_isolate', 'max_num_sta', 'ap_max_inactivity', 'airtime_bss_weight',
|
||||
'airtime_bss_limit', 'airtime_sta_weight', 'bss_load_update_period', 'chan_util_avg_period',
|
||||
@@ -69,7 +77,7 @@ function iface_authentication_server(config) {
|
||||
append_vars(config, [ 'auth_server_port', 'auth_server_shared_secret' ]);
|
||||
}
|
||||
|
||||
append_vars(config, [ 'radius_auth_req_attr' ]);
|
||||
append_list(config, [ 'radius_auth_req_attr' ]);
|
||||
}
|
||||
|
||||
function iface_accounting_server(config) {
|
||||
@@ -78,7 +86,7 @@ function iface_accounting_server(config) {
|
||||
append_vars(config, [ 'acct_server_port', 'acct_server_shared_secret' ]);
|
||||
}
|
||||
|
||||
append_vars(config, [ 'radius_acct_req_attr' ]);
|
||||
append_list(config, [ 'radius_acct_req_attr' ]);
|
||||
}
|
||||
|
||||
function iface_auth_type(config, band) {
|
||||
@@ -522,8 +530,9 @@ function iface_hs20(config) {
|
||||
append_vars(config, [
|
||||
'hs20', 'disable_dgaf', 'anqp_domain_id', 'hs20_deauth_req_timeout',
|
||||
'hs20_wan_metrics', 'hs20_operating_class', 'hs20_t_c_filename', 'hs20_t_c_timestamp',
|
||||
'hs20_t_c_server_url', 'hs20_conn_capab'
|
||||
'hs20_t_c_server_url'
|
||||
]);
|
||||
append_list(config, [ 'hs20_conn_capab' ]);
|
||||
}
|
||||
|
||||
function iface_interworking(config) {
|
||||
@@ -536,20 +545,21 @@ function iface_interworking(config) {
|
||||
config.domain_name = join(',', config.domain_name);
|
||||
|
||||
if (config.anqp_3gpp_cell_net)
|
||||
config.domain_name = join(',', config.anqp_3gpp_cell_net);
|
||||
config.anqp_3gpp_cell_net = join(';', config.anqp_3gpp_cell_net);
|
||||
|
||||
append_vars(config, [
|
||||
'interworking', 'internet', 'asra', 'uesa', 'access_network_type', 'hessid', 'venue_group',
|
||||
'venue_type', 'network_auth_type', 'gas_address3', 'roaming_consortium', 'anqp_elem', 'nai_realm',
|
||||
'venue_name', 'venue_url', 'domain_name', 'anqp_3gpp_cell_net',
|
||||
'venue_type', 'network_auth_type', 'gas_address3', 'roaming_consortium',
|
||||
'domain_name', 'anqp_3gpp_cell_net',
|
||||
]);
|
||||
append_list(config, [ 'anqp_elem', 'nai_realm', 'venue_name', 'venue_url' ]);
|
||||
}
|
||||
|
||||
export function generate(interface, data, config, vlans, stas, phy_features) {
|
||||
config.ctrl_interface = '/var/run/hostapd';
|
||||
|
||||
config.start_disabled = data.ap_start_disabled;
|
||||
iface_setup(config);
|
||||
iface_setup(config, data.phy + data.phy_suffix, data.config.num_global_macaddr, data.config.macaddr_base);
|
||||
|
||||
iface.parse_encryption(config, data.config, phy_features);
|
||||
if (data.config.band == '6g') {
|
||||
|
||||
@@ -72,6 +72,20 @@ export function append_vars(dict, keys) {
|
||||
append(key, dict[key]);
|
||||
};
|
||||
|
||||
/* emit one "key=value" line per list element (for options hostapd parses
|
||||
* one entry per line, which must not be space-joined) */
|
||||
export function append_list(dict, keys) {
|
||||
for (let key in keys) {
|
||||
let val = dict[key];
|
||||
if (val == null)
|
||||
continue;
|
||||
if (type(val) != 'array')
|
||||
val = [ val ];
|
||||
for (let v in val)
|
||||
append(key, v);
|
||||
}
|
||||
};
|
||||
|
||||
export function append_string_vars(dict, keys) {
|
||||
for (let key in keys)
|
||||
append_string(key, dict[key]);
|
||||
|
||||
@@ -474,7 +474,7 @@ function device_htmode_append(config) {
|
||||
}
|
||||
|
||||
function device_extended_features(data, flag) {
|
||||
return !!(data[flag / 8] | (1 << (flag % 8)));
|
||||
return !!(data[flag / 8] & (1 << (flag % 8)));
|
||||
}
|
||||
|
||||
function device_capabilities(config) {
|
||||
@@ -589,6 +589,10 @@ export function setup(data) {
|
||||
append('\n#num_global_macaddr', data.config.num_global_macaddr);
|
||||
if (data.config.macaddr_base)
|
||||
append('\n#macaddr_base', data.config.macaddr_base);
|
||||
if (data.config.frequency)
|
||||
append('\n#frequency', data.config.frequency);
|
||||
if (data.channel_follow)
|
||||
append('\n#channel_follow', 1);
|
||||
|
||||
let has_ap;
|
||||
for (let k, interface in data.interfaces) {
|
||||
|
||||
@@ -58,7 +58,7 @@ export function ratelist(rates) {
|
||||
};
|
||||
|
||||
function setup_sta(data, config) {
|
||||
iface.parse_encryption(config);
|
||||
iface.parse_encryption(config, data);
|
||||
|
||||
if (config.auth_type in [ 'sae', 'owe', 'eap2', 'eap192', 'dpp' ])
|
||||
config.ieee80211w = 2;
|
||||
@@ -141,6 +141,8 @@ function setup_sta(data, config) {
|
||||
|
||||
if (config.mode == 'mesh' || config.auth_type == 'sae')
|
||||
config.sae_password = `"${config.key}"`;
|
||||
else if (length(config.key) == 64)
|
||||
config.psk = config.key;
|
||||
else
|
||||
config.psk = `"${config.key}"`;
|
||||
|
||||
@@ -190,6 +192,8 @@ function setup_sta(data, config) {
|
||||
if (config.wpa_pairwise == 'GCMP') {
|
||||
config.pairwise = 'GCMP';
|
||||
config.group = 'GCMP';
|
||||
} else if (config.wpa_pairwise) {
|
||||
config.pairwise = config.wpa_pairwise;
|
||||
}
|
||||
|
||||
config.key_mgmt ??= 'NONE';
|
||||
@@ -230,6 +234,7 @@ function setup_sta(data, config) {
|
||||
'domain_match', 'domain_match2',
|
||||
'domain_suffix_match', 'domain_suffix_match2',
|
||||
'private_key', 'private_key_passwd', 'private_key2', 'private_key2_passwd',
|
||||
'dpp_connector',
|
||||
]);
|
||||
network_append_vars(config, [
|
||||
'rsn_overriding', 'scan_ssid', 'noscan', 'disabled', 'multi_ap_profile', 'multi_ap_backhaul_sta',
|
||||
@@ -238,7 +243,7 @@ function setup_sta(data, config) {
|
||||
'disable_ht', 'disable_ht40', 'disable_vht', 'vht', 'max_oper_chwidth',
|
||||
'ht40', 'beacon_int', 'ieee80211w', 'rates', 'mesh_basic_rates', 'mcast_rate',
|
||||
'bssid_blacklist', 'bssid_whitelist', 'erp', 'eap', 'phase2',
|
||||
'dpp_connector', 'dpp_csign', 'dpp_netaccesskey',
|
||||
'dpp_csign', 'dpp_netaccesskey',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ function handle_link(dev, data, up)
|
||||
};
|
||||
|
||||
if (ap && config.multicast_to_unicast != null)
|
||||
dev_data.multicast_to_unicast = config.multicast_to_unicast;
|
||||
dev_data.multicast_to_unicast = config.multicast_to_unicast ? 1 : 0;
|
||||
|
||||
if (data.type == "vif" && config.mode == "ap") {
|
||||
dev_data.wireless_proxyarp = !!config.proxy_arp;
|
||||
@@ -173,6 +173,9 @@ function wdev_teardown_cb(wdev)
|
||||
return;
|
||||
}
|
||||
|
||||
if (wdev.config_change)
|
||||
wdev_config_init(wdev);
|
||||
|
||||
wdev.setup();
|
||||
}
|
||||
|
||||
@@ -443,6 +446,14 @@ function check()
|
||||
if (!wdev_update_disabled_vifs(this))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Defer applying a new config while a handler run is in progress: the
|
||||
* running script keeps its start-time config, and the setup/teardown
|
||||
* callback re-applies once it finishes (config_change stays set).
|
||||
*/
|
||||
if (this.state != "up" && this.state != "down")
|
||||
return;
|
||||
|
||||
wdev_config_init(this);
|
||||
this.setup();
|
||||
}
|
||||
@@ -453,6 +464,14 @@ function wdev_mark_up(wdev)
|
||||
if (wdev.state != "setup")
|
||||
return;
|
||||
|
||||
if (wdev.cancel_setup || !wdev.autostart || wdev.delete) {
|
||||
delete wdev.cancel_setup;
|
||||
wdev.teardown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
wdev_reset(wdev);
|
||||
|
||||
for (let section, data in wdev.handler_data) {
|
||||
if (data.ifname)
|
||||
handle_link(data.ifname, data, true);
|
||||
@@ -536,7 +555,7 @@ function notify(req)
|
||||
function hotplug(name, add)
|
||||
{
|
||||
let dev = name;
|
||||
let m = match(name, /(.+)\.sta.+/);
|
||||
let m = match(name, /^(.+)\.sta[0-9]+$/);
|
||||
if (m)
|
||||
name = m[1];
|
||||
|
||||
@@ -594,7 +613,7 @@ function status()
|
||||
});
|
||||
}
|
||||
return {
|
||||
up: this.state == "up",
|
||||
up: this.state == "up" && !this.data.config.disabled,
|
||||
pending: this.state == "setup" || this.state == "teardown",
|
||||
autostart: this.autostart,
|
||||
disabled: !!this.data.config.disabled,
|
||||
|
||||
@@ -275,7 +275,7 @@ function config_init(uci)
|
||||
continue;
|
||||
|
||||
dev = devices[radio] = {
|
||||
name,
|
||||
name: radio,
|
||||
config,
|
||||
|
||||
vif: [],
|
||||
@@ -337,7 +337,7 @@ function config_init(uci)
|
||||
sta: []
|
||||
};
|
||||
if (vif.vlans)
|
||||
vif_data.vlans = vif.vlans;
|
||||
vif_data.vlan = vif.vlans;
|
||||
if (vif.stations)
|
||||
vif_data.sta = vif.stations;
|
||||
push(dev.vif, vif_data);
|
||||
|
||||
@@ -298,8 +298,7 @@ const phy_proto = {
|
||||
},
|
||||
|
||||
wdev_add: function(name, data) {
|
||||
let phydev = this;
|
||||
wdev_create(this.phy, name, {
|
||||
return wdev_create(this.phy, name, {
|
||||
...data,
|
||||
radio: this.radio,
|
||||
});
|
||||
|
||||
@@ -90,17 +90,6 @@ function delete_ifname(config)
|
||||
delete config[key].ifname;
|
||||
}
|
||||
|
||||
function add_existing(phydev, config)
|
||||
{
|
||||
phydev.for_each_wdev((wdev) => {
|
||||
if (config[wdev])
|
||||
return;
|
||||
|
||||
if (trim(readfile(`/sys/class/net/${wdev}/operstate`)) == "down")
|
||||
config[wdev] = {};
|
||||
});
|
||||
}
|
||||
|
||||
function usage()
|
||||
{
|
||||
warn(`Usage: ${basename(sourcepath())} <phy> <command> [<arguments>]
|
||||
@@ -137,12 +126,11 @@ const commands = {
|
||||
if (type(old_config) == "object")
|
||||
config.data = old_config;
|
||||
|
||||
add_existing(phydev, config.data);
|
||||
add_ifname(config.data);
|
||||
drop_inactive(config.data);
|
||||
|
||||
let ubus = libubus.connect();
|
||||
let data = ubus.call("hostapd", "config_get_macaddr_list", { phy: phydev.name, radio: phydev.radio ?? -1 });
|
||||
let data = ubus.call("hostapd", "config_get_macaddr_list", { phy: phydev.phy, radio: int(phydev.radio ?? -1) });
|
||||
let macaddr_list = [];
|
||||
if (type(data) == "object" && data.macaddr)
|
||||
macaddr_list = data.macaddr;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
let libubus = require("ubus");
|
||||
import * as uloop from "uloop";
|
||||
import { open, readfile, access } from "fs";
|
||||
import { wdev_remove, is_equal, vlist_new, phy_is_fullmac, phy_open, wdev_set_radio_mask, wdev_set_up } from "common";
|
||||
|
||||
@@ -130,6 +131,15 @@ function iface_freq_info(iface, config, params)
|
||||
if (freq < 4000)
|
||||
width = 0;
|
||||
|
||||
/*
|
||||
* 6 GHz has no HT Operation IE, so the secondary channel offset cannot
|
||||
* be derived the usual way. For wide channels pass a null offset so the
|
||||
* C helper auto-derives it and computes the segment centre frequency; a
|
||||
* 0 offset would make it skip the centre calculation.
|
||||
*/
|
||||
if (freq > 5925 && width > 0 && sec_offset == 0)
|
||||
sec_offset = null;
|
||||
|
||||
return hostapd.freq_info(freq, sec_offset, width);
|
||||
}
|
||||
|
||||
@@ -311,11 +321,22 @@ function iface_macaddr_init(phydev, config, macaddr_list)
|
||||
return phydev.macaddr_init(macaddr_list, macaddr_data);
|
||||
}
|
||||
|
||||
function csa_timer_cancel(name)
|
||||
{
|
||||
let timers = hostapd.data.csa_timer;
|
||||
if (timers && timers[name]) {
|
||||
timers[name].cancel();
|
||||
delete timers[name];
|
||||
}
|
||||
}
|
||||
|
||||
function iface_restart(phydev, config, old_config)
|
||||
{
|
||||
let phy = phydev.name;
|
||||
let pending = hostapd.data.pending_config[phy];
|
||||
|
||||
csa_timer_cancel(phy);
|
||||
|
||||
if (pending)
|
||||
pending.abort();
|
||||
|
||||
@@ -516,13 +537,155 @@ function get_config_bss(name, config, idx)
|
||||
return if_bss[ifname];
|
||||
}
|
||||
|
||||
const radio_chan_fields = [
|
||||
"op_class",
|
||||
"vht_oper_chwidth", "vht_oper_centr_freq_seg0_idx",
|
||||
"he_oper_chwidth", "he_oper_centr_freq_seg0_idx",
|
||||
"eht_oper_chwidth", "eht_oper_centr_freq_seg0_idx",
|
||||
];
|
||||
|
||||
function radio_line_is_chan(line)
|
||||
{
|
||||
return index(radio_chan_fields, split(line, "=", 2)[0]) >= 0;
|
||||
}
|
||||
|
||||
// The HT40+/- direction in ht_capab is channel-derived and re-applied through
|
||||
// the CSA secondary-channel offset, so strip it when comparing the base config;
|
||||
// the remaining ht_capab bits are device capabilities that require a restart.
|
||||
function radio_base(radio)
|
||||
{
|
||||
return map(filter(radio.data, (line) => !radio_line_is_chan(line)), (line) => {
|
||||
if (substr(line, 0, 9) != "ht_capab=")
|
||||
return line;
|
||||
return replace(replace(line, "[HT40+]", ""), "[HT40-]", "");
|
||||
});
|
||||
}
|
||||
|
||||
function radio_reload_class(old_radio, new_radio)
|
||||
{
|
||||
if (is_equal(old_radio, new_radio))
|
||||
return "same";
|
||||
|
||||
// anything beyond channel/width, or the channel-follow flag flipping,
|
||||
// needs a full restart
|
||||
if (!is_equal(radio_base(old_radio), radio_base(new_radio)) ||
|
||||
(!old_radio.channel_follow) != (!new_radio.channel_follow))
|
||||
return "restart";
|
||||
|
||||
// base identical and apsta flag unchanged: only treat this as a channel
|
||||
// switch if the channel or its derived width lines actually differ (the
|
||||
// derived frequency field alone appearing is not a real change)
|
||||
if (old_radio.channel == new_radio.channel &&
|
||||
is_equal(filter(old_radio.data, radio_line_is_chan),
|
||||
filter(new_radio.data, radio_line_is_chan)))
|
||||
return "same";
|
||||
|
||||
return "channel";
|
||||
}
|
||||
|
||||
function iface_channel_is_dfs(radio)
|
||||
{
|
||||
let freq = radio.frequency;
|
||||
|
||||
/* 5 GHz DFS sub-bands; 2.4 GHz and 6 GHz have no radar channels */
|
||||
return freq && ((freq >= 5250 && freq <= 5330) ||
|
||||
(freq >= 5490 && freq <= 5730));
|
||||
}
|
||||
|
||||
function iface_csa_check(name)
|
||||
{
|
||||
if (hostapd.data.csa_timer)
|
||||
delete hostapd.data.csa_timer[name];
|
||||
|
||||
let config = hostapd.data.config[name];
|
||||
let iface = hostapd.interfaces[name];
|
||||
if (!config || !iface || !iface.csa_in_progress())
|
||||
return;
|
||||
|
||||
hostapd.printf(`Config channel switch on phy ${name} did not complete, restarting`);
|
||||
let phydev = phy_open(config.phy, config.radio_idx);
|
||||
if (phydev)
|
||||
iface_restart(phydev, config, config);
|
||||
}
|
||||
|
||||
function iface_channel_switch(name, config)
|
||||
{
|
||||
let radio = config.radio;
|
||||
|
||||
/*
|
||||
* The runtime channel is followed from a co-located supplicant
|
||||
* interface (STA/mesh/adhoc) via apsta_state; the AP never picks its
|
||||
* own channel here. Adopt the new fallback channel without touching the
|
||||
* running BSSes.
|
||||
*/
|
||||
if (radio.channel_follow)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* A single iface-level CSA cannot coordinate the links of an MLD AP
|
||||
* that span multiple radios, and DFS targets need CAC before use.
|
||||
* Fall back to a full restart for both.
|
||||
*/
|
||||
for (let bss in config.bss)
|
||||
if (bss.mld_ap)
|
||||
return false;
|
||||
|
||||
if (!radio.frequency || iface_channel_is_dfs(radio))
|
||||
return false;
|
||||
|
||||
let iface = hostapd.interfaces[name];
|
||||
if (!iface || iface.state() != "ENABLED")
|
||||
return false;
|
||||
|
||||
let freq_info = iface_freq_info(iface, config, { frequency: radio.frequency });
|
||||
if (!freq_info)
|
||||
return false;
|
||||
|
||||
freq_info.csa_count = 10;
|
||||
if (!iface.switch_channel(freq_info))
|
||||
return false;
|
||||
|
||||
hostapd.printf(`Channel switch to ${radio.channel} on phy ${name}`);
|
||||
|
||||
/*
|
||||
* Verify the switch actually completes; if the driver never finishes it,
|
||||
* fall back to a full restart. Armed only here, so ubus- or apsta-
|
||||
* triggered channel switches are left to their own recovery.
|
||||
*/
|
||||
hostapd.data.csa_timer ??= {};
|
||||
csa_timer_cancel(name);
|
||||
|
||||
let beacon_int = 100;
|
||||
for (let line in config.radio.data) {
|
||||
let m = match(line, /^beacon_int=([0-9]+)/);
|
||||
if (m) {
|
||||
beacon_int = int(m[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hostapd.data.csa_timer[name] = uloop.timer(freq_info.csa_count * beacon_int + 2000,
|
||||
() => iface_csa_check(name));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function iface_reload_config(name, phydev, config, old_config)
|
||||
{
|
||||
let phy = phydev.name;
|
||||
|
||||
if (!old_config || !is_equal(old_config.radio, config.radio))
|
||||
if (!old_config)
|
||||
return false;
|
||||
|
||||
switch (radio_reload_class(old_config.radio, config.radio)) {
|
||||
case "restart":
|
||||
return false;
|
||||
case "channel":
|
||||
if (!iface_channel_switch(name, config))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_equal(old_config.bss, config.bss))
|
||||
return true;
|
||||
|
||||
@@ -696,7 +859,7 @@ function iface_reload_config(name, phydev, config, old_config)
|
||||
// with the bssid of a reused interface. reassign the reused interface
|
||||
if (!bsscfg.default_macaddr) {
|
||||
// can't update bssid of the first BSS, need to restart
|
||||
if (!mac_idx < 0)
|
||||
if (mac_idx <= 0)
|
||||
return false;
|
||||
|
||||
bsscfg = config.bss[mac_idx];
|
||||
@@ -846,6 +1009,11 @@ function iface_set_config(name, config)
|
||||
{
|
||||
let old_config = hostapd.data.config[name];
|
||||
|
||||
if (!config) {
|
||||
delete hostapd.data.config[name];
|
||||
return iface_config_remove(name, old_config);
|
||||
}
|
||||
|
||||
hostapd.data.config[name] = config;
|
||||
|
||||
let phy = config.phy;
|
||||
@@ -916,6 +1084,9 @@ function iface_load_config(phy, radio, filename)
|
||||
if (!val[0])
|
||||
continue;
|
||||
|
||||
if (substr(line, 0, 2) == "# ")
|
||||
continue;
|
||||
|
||||
if (val[0] == "interface") {
|
||||
bss = config_add_bss(config, val[1]);
|
||||
break;
|
||||
@@ -926,6 +1097,16 @@ function iface_load_config(phy, radio, filename)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val[0] == "#frequency") {
|
||||
config.radio.frequency = int(val[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val[0] == "#channel_follow") {
|
||||
config.radio.channel_follow = int(val[1]) == 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val[0] == "#num_global_macaddr")
|
||||
config[substr(val[0], 1)] = int(val[1]);
|
||||
else if (val[0] == "#macaddr_base")
|
||||
@@ -946,6 +1127,9 @@ function iface_load_config(phy, radio, filename)
|
||||
if (!val[0])
|
||||
continue;
|
||||
|
||||
if (substr(line, 0, 2) == "# ")
|
||||
continue;
|
||||
|
||||
if (val[0] == "bssid") {
|
||||
bss.bssid = lc(val[1]);
|
||||
continue;
|
||||
@@ -1070,7 +1254,7 @@ function mld_set_config(config)
|
||||
let prev_mld = { ...hostapd.data.mld };
|
||||
let new_mld = {};
|
||||
let phy_list = {};
|
||||
let new_config = !length(prev_mld) && length(new_mld);
|
||||
let new_config = !length(prev_mld) && length(config);
|
||||
|
||||
hostapd.printf(`Set MLD config: ${keys(config)}`);
|
||||
|
||||
|
||||
@@ -552,6 +552,8 @@ let main_obj = {
|
||||
for (let ifname in phy.data)
|
||||
iface_stop(phy.data[ifname]);
|
||||
for (let name, data in wpas.data.mld) {
|
||||
if (data.phy != phy.name)
|
||||
continue;
|
||||
data.radio_mask_present &= ~radio_mask;
|
||||
if (data.radio_mask_up & radio_mask)
|
||||
mld_update_iface(name, data);
|
||||
@@ -561,6 +563,8 @@ let main_obj = {
|
||||
|
||||
let found;
|
||||
for (let name, data in wpas.data.mld) {
|
||||
if (data.phy != phy.name)
|
||||
continue;
|
||||
if (!(data.radio_mask & radio_mask))
|
||||
continue;
|
||||
data.radio_mask_present |= radio_mask;
|
||||
@@ -604,9 +608,12 @@ let main_obj = {
|
||||
|
||||
let ifnames = keys(phy.data);
|
||||
let radio_mask = phy.radio != null ? (1 << phy.radio) : 0;
|
||||
for (let name, data in wpas.data.mld)
|
||||
for (let name, data in wpas.data.mld) {
|
||||
if (data.phy != phy.name)
|
||||
continue;
|
||||
if (data.radio_mask_up & radio_mask)
|
||||
push(ifnames, name);
|
||||
}
|
||||
|
||||
for (let ifname in ifnames) {
|
||||
try {
|
||||
|
||||
@@ -297,6 +297,14 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
|
||||
started = hapd->started;
|
||||
__uc_hostapd_bss_stop(hapd);
|
||||
|
||||
/*
|
||||
* start_disabled is only meaningful for the initial apsta bring-up. When
|
||||
* re-applying config to a BSS that was already started, clear it so the
|
||||
* restart keeps beaconing instead of silently going quiet.
|
||||
*/
|
||||
if (started)
|
||||
conf->bss[idx]->start_disabled = 0;
|
||||
|
||||
old_bss = hapd->conf;
|
||||
for (i = 0; i < iface->conf->num_bss; i++)
|
||||
if (iface->conf->bss[i] == hapd->conf)
|
||||
@@ -372,6 +380,9 @@ uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
|
||||
|
||||
hostapd_drv_stop_ap(hapd);
|
||||
hostapd_bss_deinit(hapd);
|
||||
/* deinit skips these for a bss that never started; both are idempotent */
|
||||
hostapd_ucode_free_bss(hapd);
|
||||
hostapd_ubus_free_bss(hapd);
|
||||
hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
|
||||
hostapd_config_free_bss(hapd->conf);
|
||||
#ifdef CONFIG_IEEE80211BE
|
||||
@@ -420,7 +431,7 @@ uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
|
||||
struct hostapd_bss_config *bss;
|
||||
struct hostapd_config *conf;
|
||||
struct hostapd_config *conf = NULL;
|
||||
struct hostapd_data *hapd;
|
||||
uc_value_t *file = uc_fn_arg(0);
|
||||
uc_value_t *index = uc_fn_arg(1);
|
||||
@@ -739,10 +750,22 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs)
|
||||
intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
|
||||
if (errno)
|
||||
intval = hostapd_get_oper_chwidth(conf);
|
||||
if (intval)
|
||||
csa.freq_params.bandwidth = 40 << intval;
|
||||
else
|
||||
switch (intval) {
|
||||
case CONF_OPER_CHWIDTH_80MHZ:
|
||||
case CONF_OPER_CHWIDTH_80P80MHZ:
|
||||
/* 80+80 uses an 80 MHz primary segment plus center_freq2 */
|
||||
csa.freq_params.bandwidth = 80;
|
||||
break;
|
||||
case CONF_OPER_CHWIDTH_160MHZ:
|
||||
csa.freq_params.bandwidth = 160;
|
||||
break;
|
||||
case CONF_OPER_CHWIDTH_320MHZ:
|
||||
csa.freq_params.bandwidth = 320;
|
||||
break;
|
||||
default:
|
||||
csa.freq_params.bandwidth = csa.freq_params.sec_channel_offset ? 40 : 20;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL))) && !errno)
|
||||
csa.freq_params.freq = intval;
|
||||
@@ -757,6 +780,17 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs)
|
||||
return ucv_boolean_new(!ret);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_hostapd_iface_csa_in_progress(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
|
||||
|
||||
if (!iface)
|
||||
return NULL;
|
||||
|
||||
return ucv_boolean_new(hostapd_csa_in_progress(iface));
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
@@ -840,13 +874,15 @@ int hostapd_ucode_sta_auth(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
size_t str_len;
|
||||
|
||||
cur_psk = ucv_array_get(cur, i);
|
||||
if (ucv_type(cur_psk) != UC_STRING)
|
||||
continue;
|
||||
str = ucv_string_get(cur_psk);
|
||||
str_len = strlen(str);
|
||||
if (!str || str_len < 8 || str_len > 64)
|
||||
if (str_len < 8 || str_len > 64)
|
||||
continue;
|
||||
|
||||
p = os_zalloc(sizeof(*p));
|
||||
if (len == 64) {
|
||||
if (str_len == 64) {
|
||||
if (hexstr2bin(str, p->psk, PMK_LEN) < 0) {
|
||||
free(p);
|
||||
continue;
|
||||
@@ -1213,6 +1249,7 @@ int hostapd_ucode_init(struct hapd_interfaces *ifaces)
|
||||
{ "stop", uc_hostapd_iface_stop },
|
||||
{ "start", uc_hostapd_iface_start },
|
||||
{ "switch_channel", uc_hostapd_iface_switch_channel },
|
||||
{ "csa_in_progress", uc_hostapd_iface_csa_in_progress },
|
||||
};
|
||||
uc_value_t *data, *proto;
|
||||
|
||||
@@ -1280,9 +1317,10 @@ void hostapd_ucode_free_bss(struct hostapd_data *hapd)
|
||||
if (wpa_ucode_call_prepare("bss_remove"))
|
||||
return;
|
||||
|
||||
uc_value_push(ucv_string_new(hapd->iface->phy));
|
||||
uc_value_push(ucv_string_new(hapd->conf->iface));
|
||||
uc_value_push(ucv_get(val));
|
||||
ucv_put(wpa_ucode_call(2));
|
||||
ucv_put(wpa_ucode_call(3));
|
||||
|
||||
ucv_put(val);
|
||||
}
|
||||
|
||||
@@ -139,6 +139,9 @@ uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs)
|
||||
case 2:
|
||||
chanwidth = CONF_OPER_CHWIDTH_160MHZ;
|
||||
break;
|
||||
case 3:
|
||||
chanwidth = CONF_OPER_CHWIDTH_320MHZ;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ethtool
|
||||
PKG_VERSION:=7.0
|
||||
PKG_VERSION:=7.1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
|
||||
PKG_SOURCE_URL:=@KERNEL/software/network/ethtool
|
||||
PKG_HASH:=660bf9725a7871343a0d232068a7634fbcfb69b6c2f8eff455827faefb0cd162
|
||||
PKG_HASH:=4d78c26edc0255bc92f4b995b5fd66108d75ff966ed4694f6025a6d370bc2496
|
||||
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
PKG_LICENSE_FILES:=COPYING
|
||||
|
||||
@@ -215,7 +215,7 @@ fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
|
||||
memmove(desc, last, end - tmp);
|
||||
if (desc < last) {
|
||||
tmp = end - (last - desc) * sizeof(struct fis_image_desc);
|
||||
memset(tmp, 0xff, tmp - end);
|
||||
memset(tmp, 0xff, end - tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/rpcd.git
|
||||
PKG_MIRROR_HASH:=b15b42e9f27a35030f488d7a61a3b2f505f79b5675455b20f1336acb1d99686a
|
||||
PKG_SOURCE_DATE:=2026-06-04
|
||||
PKG_SOURCE_VERSION:=28faf6403792d25b9826043aaf37880624c19568
|
||||
PKG_MIRROR_HASH:=ca2498a25c69e6b6e8fe1bcc5865a244e409674b1ac2e2e36c0e4bb04b11aba8
|
||||
PKG_SOURCE_DATE:=2026-07-19
|
||||
PKG_SOURCE_VERSION:=e37ed9d814699098eb7e26c8b33c054840782dfb
|
||||
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
|
||||
|
||||
PKG_LICENSE:=ISC
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ucode-mod-bpf
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
PKG_LICENSE:=ISC
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ struct uc_bpf_fd {
|
||||
|
||||
struct uc_bpf_map {
|
||||
struct uc_bpf_fd fd; /* must be first */
|
||||
unsigned int type;
|
||||
unsigned int key_size, val_size;
|
||||
unsigned int max_entries;
|
||||
};
|
||||
|
||||
struct uc_bpf_map_iter {
|
||||
@@ -129,7 +131,7 @@ uc_bpf_module_set_opts(struct bpf_object *obj, uc_value_t *opts)
|
||||
}
|
||||
|
||||
if (!map)
|
||||
err_return_int(errno, "rodata map");
|
||||
err_return_int(ENOENT, "rodata map");
|
||||
|
||||
if (bpf_map__set_initial_value(map, ucv_string_get(val),
|
||||
ucv_string_length(val)))
|
||||
@@ -187,8 +189,9 @@ uc_bpf_open_module(uc_vm_t *vm, size_t nargs)
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_map_create(uc_vm_t *vm, uc_value_t *mod, int fd, unsigned int key_size,
|
||||
unsigned int val_size, bool close)
|
||||
uc_bpf_map_create(uc_vm_t *vm, uc_value_t *mod, int fd, unsigned int type,
|
||||
unsigned int key_size, unsigned int val_size,
|
||||
unsigned int max_entries, bool close)
|
||||
{
|
||||
struct uc_bpf_map *uc_map;
|
||||
uc_value_t *res;
|
||||
@@ -196,8 +199,10 @@ uc_bpf_map_create(uc_vm_t *vm, uc_value_t *mod, int fd, unsigned int key_size,
|
||||
res = ucv_resource_create_ex(vm, "bpf.map", (void **)&uc_map, 1, sizeof(*uc_map));
|
||||
ucv_resource_value_set(res, 0, ucv_get(mod));
|
||||
uc_map->fd.fd = fd;
|
||||
uc_map->type = type;
|
||||
uc_map->key_size = key_size;
|
||||
uc_map->val_size = val_size;
|
||||
uc_map->max_entries = max_entries;
|
||||
uc_map->fd.close = close;
|
||||
|
||||
return res;
|
||||
@@ -218,12 +223,26 @@ uc_bpf_prog_create(uc_vm_t *vm, uc_value_t *mod, int fd, bool close)
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_open_map(uc_vm_t *vm, size_t nargs)
|
||||
uc_bpf_open_map_fd(uc_vm_t *vm, int fd)
|
||||
{
|
||||
struct bpf_map_info info;
|
||||
uc_value_t *path = uc_fn_arg(0);
|
||||
__u32 len = sizeof(info);
|
||||
int err;
|
||||
|
||||
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
||||
if (err) {
|
||||
close(fd);
|
||||
err_return(errno, NULL);
|
||||
}
|
||||
|
||||
return uc_bpf_map_create(vm, NULL, fd, info.type, info.key_size,
|
||||
info.value_size, info.max_entries, true);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_open_map(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
uc_value_t *path = uc_fn_arg(0);
|
||||
int fd;
|
||||
|
||||
if (ucv_type(path) != UC_STRING)
|
||||
@@ -233,13 +252,23 @@ uc_bpf_open_map(uc_vm_t *vm, size_t nargs)
|
||||
if (fd < 0)
|
||||
err_return(errno, NULL);
|
||||
|
||||
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
||||
if (err) {
|
||||
close(fd);
|
||||
err_return(errno, NULL);
|
||||
}
|
||||
return uc_bpf_open_map_fd(vm, fd);
|
||||
}
|
||||
|
||||
return uc_bpf_map_create(vm, NULL, fd, info.key_size, info.value_size, true);
|
||||
static uc_value_t *
|
||||
uc_bpf_open_map_id(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
uc_value_t *id = uc_fn_arg(0);
|
||||
int fd;
|
||||
|
||||
if (ucv_type(id) != UC_INTEGER)
|
||||
err_return(EINVAL, "map id");
|
||||
|
||||
fd = bpf_map_get_fd_by_id(ucv_int64_get(id));
|
||||
if (fd < 0)
|
||||
err_return(errno, NULL);
|
||||
|
||||
return uc_bpf_open_map_fd(vm, fd);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
@@ -258,6 +287,22 @@ uc_bpf_open_program(uc_vm_t *vm, size_t nargs)
|
||||
return uc_bpf_prog_create(vm, NULL, fd, true);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_open_program_id(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
uc_value_t *id = uc_fn_arg(0);
|
||||
int fd;
|
||||
|
||||
if (ucv_type(id) != UC_INTEGER)
|
||||
err_return(EINVAL, "program id");
|
||||
|
||||
fd = bpf_prog_get_fd_by_id(ucv_int64_get(id));
|
||||
if (fd < 0)
|
||||
err_return(errno, NULL);
|
||||
|
||||
return uc_bpf_prog_create(vm, NULL, fd, true);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_module_get_maps(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
@@ -295,7 +340,9 @@ uc_bpf_module_get_map(uc_vm_t *vm, size_t nargs)
|
||||
if (fd < 0)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
return uc_bpf_map_create(vm, _uc_fn_this_res(vm), fd, bpf_map__key_size(map), bpf_map__value_size(map), false);
|
||||
return uc_bpf_map_create(vm, _uc_fn_this_res(vm), fd, bpf_map__type(map),
|
||||
bpf_map__key_size(map), bpf_map__value_size(map),
|
||||
bpf_map__max_entries(map), false);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
@@ -339,28 +386,40 @@ uc_bpf_module_get_program(uc_vm_t *vm, size_t nargs)
|
||||
}
|
||||
|
||||
static void *
|
||||
uc_bpf_map_arg(uc_value_t *val, const char *kind, unsigned int size)
|
||||
uc_bpf_map_arg(uc_value_t *val, const char *kind, unsigned int size,
|
||||
uint64_t *val_int)
|
||||
{
|
||||
static union {
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} val_int;
|
||||
|
||||
switch (ucv_type(val)) {
|
||||
case UC_INTEGER:
|
||||
if (size == 4)
|
||||
val_int.u32 = ucv_int64_get(val);
|
||||
*(uint32_t *)val_int = ucv_int64_get(val);
|
||||
else if (size == 8)
|
||||
val_int.u64 = ucv_int64_get(val);
|
||||
*val_int = ucv_int64_get(val);
|
||||
else
|
||||
break;
|
||||
|
||||
return &val_int;
|
||||
return val_int;
|
||||
case UC_STRING:
|
||||
if (size != ucv_string_length(val))
|
||||
break;
|
||||
|
||||
return ucv_string_get(val);
|
||||
case UC_RESOURCE: {
|
||||
struct uc_bpf_fd *f;
|
||||
|
||||
f = ucv_resource_data(val, "bpf.map");
|
||||
if (!f)
|
||||
f = ucv_resource_data(val, "bpf.program");
|
||||
if (!f)
|
||||
err_return(EINVAL, "%s type", kind);
|
||||
|
||||
if (size != 4)
|
||||
break;
|
||||
|
||||
*(uint32_t *)val_int = f->fd;
|
||||
|
||||
return val_int;
|
||||
}
|
||||
default:
|
||||
err_return(EINVAL, "%s type", kind);
|
||||
}
|
||||
@@ -368,25 +427,174 @@ uc_bpf_map_arg(uc_value_t *val, const char *kind, unsigned int size)
|
||||
err_return(EINVAL, "%s size mismatch (expected: %d)", kind, size);
|
||||
}
|
||||
|
||||
static bool
|
||||
uc_bpf_map_key_arg(struct uc_bpf_map *map, uc_value_t *a_key, uint64_t *buf,
|
||||
void **key)
|
||||
{
|
||||
if (!map->key_size) {
|
||||
if (a_key) {
|
||||
set_error(EINVAL, "map has no key");
|
||||
return false;
|
||||
}
|
||||
|
||||
*key = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
*key = uc_bpf_map_arg(a_key, "key", map->key_size, buf);
|
||||
|
||||
return *key != NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
uc_bpf_map_is_percpu(struct uc_bpf_map *map)
|
||||
{
|
||||
switch (map->type) {
|
||||
case BPF_MAP_TYPE_PERCPU_HASH:
|
||||
case BPF_MAP_TYPE_PERCPU_ARRAY:
|
||||
case BPF_MAP_TYPE_LRU_PERCPU_HASH:
|
||||
case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
uc_bpf_map_val_stride(struct uc_bpf_map *map)
|
||||
{
|
||||
return (map->val_size + 7) & ~7U;
|
||||
}
|
||||
|
||||
static bool
|
||||
uc_bpf_map_val_len(struct uc_bpf_map *map, unsigned int *len, int *num_cpus)
|
||||
{
|
||||
*len = map->val_size;
|
||||
*num_cpus = 1;
|
||||
|
||||
if (!uc_bpf_map_is_percpu(map))
|
||||
return true;
|
||||
|
||||
*num_cpus = libbpf_num_possible_cpus();
|
||||
if (*num_cpus <= 0) {
|
||||
set_error(errno, "number of CPUs");
|
||||
return false;
|
||||
}
|
||||
|
||||
*len = uc_bpf_map_val_stride(map) * *num_cpus;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_map_val_read(uc_vm_t *vm, struct uc_bpf_map *map, void *val,
|
||||
int num_cpus)
|
||||
{
|
||||
unsigned int stride = uc_bpf_map_val_stride(map);
|
||||
uc_value_t *rv;
|
||||
int i;
|
||||
|
||||
if (!uc_bpf_map_is_percpu(map))
|
||||
return ucv_string_new_length(val, map->val_size);
|
||||
|
||||
rv = ucv_array_new(vm);
|
||||
for (i = 0; i < num_cpus; i++)
|
||||
ucv_array_set(rv, i, ucv_string_new_length((char *)val + i * stride,
|
||||
map->val_size));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool
|
||||
uc_bpf_map_val_copy(struct uc_bpf_map *map, uc_value_t *a_val, void *dest)
|
||||
{
|
||||
uint64_t val_int;
|
||||
void *val;
|
||||
|
||||
val = uc_bpf_map_arg(a_val, "value", map->val_size, &val_int);
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
memcpy(dest, val, map->val_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *
|
||||
uc_bpf_map_val_arg(struct uc_bpf_map *map, uc_value_t *a_val, void *buf,
|
||||
int num_cpus)
|
||||
{
|
||||
unsigned int stride = uc_bpf_map_val_stride(map);
|
||||
int i;
|
||||
|
||||
if (!uc_bpf_map_is_percpu(map))
|
||||
return uc_bpf_map_arg(a_val, "value", map->val_size, buf);
|
||||
|
||||
memset(buf, 0, stride * num_cpus);
|
||||
if (ucv_type(a_val) != UC_ARRAY) {
|
||||
if (!uc_bpf_map_val_copy(map, a_val, buf))
|
||||
return NULL;
|
||||
|
||||
for (i = 1; i < num_cpus; i++)
|
||||
memcpy((char *)buf + i * stride, buf, map->val_size);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (ucv_array_length(a_val) != (size_t)num_cpus)
|
||||
err_return(EINVAL, "value count mismatch (expected: %d)", num_cpus);
|
||||
|
||||
for (i = 0; i < num_cpus; i++)
|
||||
if (!uc_bpf_map_val_copy(map, ucv_array_get(a_val, i),
|
||||
(char *)buf + i * stride))
|
||||
return NULL;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_map_info(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
|
||||
uc_value_t *rv;
|
||||
|
||||
if (!map)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
rv = ucv_object_new(vm);
|
||||
ucv_object_add(rv, "type", ucv_int64_new(map->type));
|
||||
ucv_object_add(rv, "key_size", ucv_int64_new(map->key_size));
|
||||
ucv_object_add(rv, "value_size", ucv_int64_new(map->val_size));
|
||||
ucv_object_add(rv, "max_entries", ucv_int64_new(map->max_entries));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_map_get(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
|
||||
uc_value_t *a_key = uc_fn_arg(0);
|
||||
unsigned int val_len;
|
||||
uint64_t key_int;
|
||||
void *key, *val;
|
||||
int num_cpus;
|
||||
|
||||
if (!map)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
key = uc_bpf_map_arg(a_key, "key", map->key_size);
|
||||
if (!key)
|
||||
if (!uc_bpf_map_key_arg(map, a_key, &key_int, &key))
|
||||
return NULL;
|
||||
|
||||
val = alloca(map->val_size);
|
||||
if (!uc_bpf_map_val_len(map, &val_len, &num_cpus))
|
||||
return NULL;
|
||||
|
||||
val = alloca(val_len);
|
||||
if (bpf_map_lookup_elem(map->fd.fd, key, val))
|
||||
return NULL;
|
||||
|
||||
return ucv_string_new_length(val, map->val_size);
|
||||
return uc_bpf_map_val_read(vm, map, val, num_cpus);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
@@ -396,17 +604,23 @@ uc_bpf_map_set(uc_vm_t *vm, size_t nargs)
|
||||
uc_value_t *a_key = uc_fn_arg(0);
|
||||
uc_value_t *a_val = uc_fn_arg(1);
|
||||
uc_value_t *a_flags = uc_fn_arg(2);
|
||||
unsigned int val_len;
|
||||
uint64_t key_int;
|
||||
uint64_t flags;
|
||||
void *key, *val;
|
||||
int num_cpus;
|
||||
|
||||
if (!map)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
key = uc_bpf_map_arg(a_key, "key", map->key_size);
|
||||
if (!key)
|
||||
if (!uc_bpf_map_key_arg(map, a_key, &key_int, &key))
|
||||
return NULL;
|
||||
|
||||
val = uc_bpf_map_arg(a_val, "value", map->val_size);
|
||||
if (!uc_bpf_map_val_len(map, &val_len, &num_cpus))
|
||||
return NULL;
|
||||
|
||||
val = alloca(val_len);
|
||||
val = uc_bpf_map_val_arg(map, a_val, val, num_cpus);
|
||||
if (!val)
|
||||
return NULL;
|
||||
|
||||
@@ -420,7 +634,7 @@ uc_bpf_map_set(uc_vm_t *vm, size_t nargs)
|
||||
if (bpf_map_update_elem(map->fd.fd, key, val, flags))
|
||||
return NULL;
|
||||
|
||||
return ucv_string_new_length(val, map->val_size);
|
||||
return uc_bpf_map_val_read(vm, map, val, num_cpus);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
@@ -429,14 +643,16 @@ uc_bpf_map_delete(uc_vm_t *vm, size_t nargs)
|
||||
struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
|
||||
uc_value_t *a_key = uc_fn_arg(0);
|
||||
uc_value_t *a_return = uc_fn_arg(1);
|
||||
unsigned int val_len;
|
||||
void *key, *val = NULL;
|
||||
uint64_t key_int;
|
||||
int num_cpus;
|
||||
int ret;
|
||||
|
||||
if (!map)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
key = uc_bpf_map_arg(a_key, "key", map->key_size);
|
||||
if (!key)
|
||||
if (!uc_bpf_map_key_arg(map, a_key, &key_int, &key))
|
||||
return NULL;
|
||||
|
||||
if (!ucv_is_truish(a_return)) {
|
||||
@@ -445,11 +661,14 @@ uc_bpf_map_delete(uc_vm_t *vm, size_t nargs)
|
||||
return ucv_boolean_new(ret == 0);
|
||||
}
|
||||
|
||||
val = alloca(map->val_size);
|
||||
if (!uc_bpf_map_val_len(map, &val_len, &num_cpus))
|
||||
return NULL;
|
||||
|
||||
val = alloca(val_len);
|
||||
if (bpf_map_lookup_and_delete_elem(map->fd.fd, key, val))
|
||||
return NULL;
|
||||
|
||||
return ucv_string_new_length(val, map->val_size);
|
||||
return uc_bpf_map_val_read(vm, map, val, num_cpus);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
@@ -520,6 +739,9 @@ uc_bpf_map_iter_next(uc_vm_t *vm, size_t nargs)
|
||||
struct uc_bpf_map_iter *iter = uc_fn_thisval("bpf.map_iter");
|
||||
uc_value_t *rv;
|
||||
|
||||
if (!iter)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
if (!iter->has_next)
|
||||
return NULL;
|
||||
|
||||
@@ -536,15 +758,22 @@ uc_bpf_map_iter_next_int(uc_vm_t *vm, size_t nargs)
|
||||
uint64_t intval;
|
||||
uc_value_t *rv;
|
||||
|
||||
if (!iter)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
if (!iter->has_next)
|
||||
return NULL;
|
||||
|
||||
if (iter->key_size == 4)
|
||||
intval = *(uint32_t *)iter->key;
|
||||
else if (iter->key_size == 8)
|
||||
intval = *(uint64_t *)iter->key;
|
||||
else
|
||||
if (iter->key_size == 4) {
|
||||
uint32_t val32;
|
||||
|
||||
memcpy(&val32, iter->key, sizeof(val32));
|
||||
intval = val32;
|
||||
} else if (iter->key_size == 8) {
|
||||
memcpy(&intval, iter->key, sizeof(intval));
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rv = ucv_int64_new(intval);
|
||||
iter->has_next = !bpf_map_get_next_key(iter->fd, &iter->key, &iter->key);
|
||||
@@ -561,6 +790,9 @@ uc_bpf_map_foreach(uc_vm_t *vm, size_t nargs)
|
||||
void *key, *next;
|
||||
bool ret = false;
|
||||
|
||||
if (!map)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
key = alloca(map->key_size);
|
||||
next = alloca(map->key_size);
|
||||
has_next = !bpf_map_get_next_key(map->fd.fd, NULL, next);
|
||||
@@ -591,12 +823,250 @@ uc_bpf_map_foreach(uc_vm_t *vm, size_t nargs)
|
||||
return ucv_boolean_new(ret);
|
||||
}
|
||||
|
||||
enum {
|
||||
UC_BPF_BUF_CB,
|
||||
UC_BPF_BUF_LOST_CB,
|
||||
UC_BPF_BUF_MAP,
|
||||
__UC_BPF_BUF_MAX
|
||||
};
|
||||
|
||||
struct uc_bpf_buffer {
|
||||
uc_vm_t *vm;
|
||||
uc_value_t *res;
|
||||
bool perf;
|
||||
bool exception;
|
||||
union {
|
||||
struct ring_buffer *rb;
|
||||
struct perf_buffer *pb;
|
||||
};
|
||||
};
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_buffer_call(struct uc_bpf_buffer *buf, size_t slot, uc_value_t *arg,
|
||||
int cpu)
|
||||
{
|
||||
uc_vm_t *vm = buf->vm;
|
||||
size_t fn_nargs = 1;
|
||||
|
||||
uc_vm_stack_push(vm, ucv_get(ucv_resource_value_get(buf->res, slot)));
|
||||
uc_vm_stack_push(vm, arg);
|
||||
if (cpu >= 0) {
|
||||
uc_vm_stack_push(vm, ucv_int64_new(cpu));
|
||||
fn_nargs++;
|
||||
}
|
||||
|
||||
if (uc_vm_call(vm, false, fn_nargs) != EXCEPTION_NONE) {
|
||||
buf->exception = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return uc_vm_stack_pop(vm);
|
||||
}
|
||||
|
||||
static int
|
||||
uc_bpf_ringbuf_sample(void *ctx, void *data, size_t size)
|
||||
{
|
||||
struct uc_bpf_buffer *buf = ctx;
|
||||
uc_value_t *rv;
|
||||
int ret = 0;
|
||||
|
||||
if (buf->exception)
|
||||
return -1;
|
||||
|
||||
rv = uc_bpf_buffer_call(buf, UC_BPF_BUF_CB,
|
||||
ucv_string_new_length(data, size), -1);
|
||||
if (buf->exception)
|
||||
return -1;
|
||||
|
||||
if (ucv_type(rv) == UC_INTEGER)
|
||||
ret = ucv_int64_get(rv);
|
||||
ucv_put(rv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
uc_bpf_perf_sample(void *ctx, int cpu, void *data, __u32 size)
|
||||
{
|
||||
struct uc_bpf_buffer *buf = ctx;
|
||||
|
||||
if (buf->exception)
|
||||
return;
|
||||
|
||||
ucv_put(uc_bpf_buffer_call(buf, UC_BPF_BUF_CB,
|
||||
ucv_string_new_length(data, size), cpu));
|
||||
}
|
||||
|
||||
static void
|
||||
uc_bpf_perf_lost(void *ctx, int cpu, __u64 cnt)
|
||||
{
|
||||
struct uc_bpf_buffer *buf = ctx;
|
||||
|
||||
if (buf->exception || !ucv_resource_value_get(buf->res, UC_BPF_BUF_LOST_CB))
|
||||
return;
|
||||
|
||||
ucv_put(uc_bpf_buffer_call(buf, UC_BPF_BUF_LOST_CB, ucv_int64_new(cnt),
|
||||
cpu));
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_map_buffer_create(uc_vm_t *vm, struct uc_bpf_map *map, bool perf,
|
||||
size_t pages, uc_value_t *cb, uc_value_t *lost_cb)
|
||||
{
|
||||
struct uc_bpf_buffer *buf;
|
||||
uc_value_t *res;
|
||||
|
||||
res = ucv_resource_create_ex(vm, "bpf.buffer", (void **)&buf,
|
||||
__UC_BPF_BUF_MAX, sizeof(*buf));
|
||||
buf->vm = vm;
|
||||
buf->res = res;
|
||||
buf->perf = perf;
|
||||
if (perf)
|
||||
buf->pb = perf_buffer__new(map->fd.fd, pages, uc_bpf_perf_sample,
|
||||
uc_bpf_perf_lost, buf, NULL);
|
||||
else
|
||||
buf->rb = ring_buffer__new(map->fd.fd, uc_bpf_ringbuf_sample,
|
||||
buf, NULL);
|
||||
if (!buf->rb) {
|
||||
ucv_put(res);
|
||||
err_return(errno, NULL);
|
||||
}
|
||||
|
||||
ucv_resource_value_set(res, UC_BPF_BUF_CB, ucv_get(cb));
|
||||
ucv_resource_value_set(res, UC_BPF_BUF_LOST_CB, ucv_get(lost_cb));
|
||||
ucv_resource_value_set(res, UC_BPF_BUF_MAP, ucv_get(_uc_fn_this_res(vm)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_map_ringbuf(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
|
||||
uc_value_t *cb = uc_fn_arg(0);
|
||||
|
||||
if (!map)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
if (map->type != BPF_MAP_TYPE_RINGBUF)
|
||||
err_return(EINVAL, "map type");
|
||||
|
||||
if (!ucv_is_callable(cb))
|
||||
err_return(EINVAL, "callback");
|
||||
|
||||
return uc_bpf_map_buffer_create(vm, map, false, 0, cb, NULL);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_map_perf_buffer(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
|
||||
uc_value_t *cb = uc_fn_arg(0);
|
||||
uc_value_t *a_pages = uc_fn_arg(1);
|
||||
uc_value_t *lost_cb = uc_fn_arg(2);
|
||||
size_t pages = 8;
|
||||
|
||||
if (!map)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
if (map->type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
|
||||
err_return(EINVAL, "map type");
|
||||
|
||||
if (!ucv_is_callable(cb))
|
||||
err_return(EINVAL, "callback");
|
||||
|
||||
if (a_pages) {
|
||||
if (ucv_type(a_pages) != UC_INTEGER || ucv_int64_get(a_pages) <= 0)
|
||||
err_return(EINVAL, "page count");
|
||||
|
||||
pages = ucv_int64_get(a_pages);
|
||||
}
|
||||
|
||||
if (lost_cb && !ucv_is_callable(lost_cb))
|
||||
err_return(EINVAL, "lost callback");
|
||||
|
||||
return uc_bpf_map_buffer_create(vm, map, true, pages, cb, lost_cb);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_buffer_fileno(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct uc_bpf_buffer *buf = uc_fn_thisval("bpf.buffer");
|
||||
int fd;
|
||||
|
||||
if (!buf)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
fd = buf->perf ? perf_buffer__epoll_fd(buf->pb) :
|
||||
ring_buffer__epoll_fd(buf->rb);
|
||||
if (fd < 0)
|
||||
err_return(errno, NULL);
|
||||
|
||||
return ucv_int64_new(fd);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_buffer_result(uc_vm_t *vm, struct uc_bpf_buffer *buf, int ret)
|
||||
{
|
||||
if (buf->exception) {
|
||||
buf->exception = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
err_return(errno, NULL);
|
||||
|
||||
return ucv_int64_new(ret);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_buffer_poll(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct uc_bpf_buffer *buf = uc_fn_thisval("bpf.buffer");
|
||||
uc_value_t *a_timeout = uc_fn_arg(0);
|
||||
int timeout = 0;
|
||||
int ret;
|
||||
|
||||
if (!buf)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
if (a_timeout) {
|
||||
if (ucv_type(a_timeout) != UC_INTEGER)
|
||||
err_return(EINVAL, "timeout");
|
||||
|
||||
timeout = ucv_int64_get(a_timeout);
|
||||
}
|
||||
|
||||
ret = buf->perf ? perf_buffer__poll(buf->pb, timeout) :
|
||||
ring_buffer__poll(buf->rb, timeout);
|
||||
|
||||
return uc_bpf_buffer_result(vm, buf, ret);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_buffer_consume(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct uc_bpf_buffer *buf = uc_fn_thisval("bpf.buffer");
|
||||
int ret;
|
||||
|
||||
if (!buf)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
ret = buf->perf ? perf_buffer__consume(buf->pb) :
|
||||
ring_buffer__consume(buf->rb);
|
||||
|
||||
return uc_bpf_buffer_result(vm, buf, ret);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_bpf_obj_pin(uc_vm_t *vm, size_t nargs, const char *type)
|
||||
{
|
||||
struct uc_bpf_fd *f = uc_fn_thisval(type);
|
||||
uc_value_t *path = uc_fn_arg(0);
|
||||
|
||||
if (!f)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
if (ucv_type(path) != UC_STRING)
|
||||
err_return(EINVAL, NULL);
|
||||
|
||||
@@ -665,9 +1135,7 @@ out:
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (fd >= 0)
|
||||
err_return(ENOENT, NULL);
|
||||
return NULL;
|
||||
err_return(errno, NULL);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
@@ -752,6 +1220,23 @@ register_constants(uc_vm_t *vm, uc_value_t *scope)
|
||||
ADD_CONST(BPF_PROG_TYPE_SCHED_CLS);
|
||||
ADD_CONST(BPF_PROG_TYPE_SCHED_ACT);
|
||||
|
||||
ADD_CONST(BPF_MAP_TYPE_HASH);
|
||||
ADD_CONST(BPF_MAP_TYPE_ARRAY);
|
||||
ADD_CONST(BPF_MAP_TYPE_PROG_ARRAY);
|
||||
ADD_CONST(BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
ADD_CONST(BPF_MAP_TYPE_PERCPU_HASH);
|
||||
ADD_CONST(BPF_MAP_TYPE_PERCPU_ARRAY);
|
||||
ADD_CONST(BPF_MAP_TYPE_LRU_HASH);
|
||||
ADD_CONST(BPF_MAP_TYPE_LRU_PERCPU_HASH);
|
||||
ADD_CONST(BPF_MAP_TYPE_LPM_TRIE);
|
||||
ADD_CONST(BPF_MAP_TYPE_ARRAY_OF_MAPS);
|
||||
ADD_CONST(BPF_MAP_TYPE_HASH_OF_MAPS);
|
||||
ADD_CONST(BPF_MAP_TYPE_DEVMAP);
|
||||
ADD_CONST(BPF_MAP_TYPE_SOCKMAP);
|
||||
ADD_CONST(BPF_MAP_TYPE_QUEUE);
|
||||
ADD_CONST(BPF_MAP_TYPE_STACK);
|
||||
ADD_CONST(BPF_MAP_TYPE_RINGBUF);
|
||||
|
||||
ADD_CONST(BPF_ANY);
|
||||
ADD_CONST(BPF_NOEXIST);
|
||||
ADD_CONST(BPF_EXIST);
|
||||
@@ -774,12 +1259,31 @@ static void module_free(void *ptr)
|
||||
|
||||
static const uc_function_list_t map_fns[] = {
|
||||
{ "pin", uc_bpf_map_pin },
|
||||
{ "info", uc_bpf_map_info },
|
||||
{ "get", uc_bpf_map_get },
|
||||
{ "set", uc_bpf_map_set },
|
||||
{ "delete", uc_bpf_map_delete },
|
||||
{ "delete_all", uc_bpf_map_delete_all },
|
||||
{ "foreach", uc_bpf_map_foreach },
|
||||
{ "iterator", uc_bpf_map_iterator },
|
||||
{ "ringbuf", uc_bpf_map_ringbuf },
|
||||
{ "perf_buffer", uc_bpf_map_perf_buffer },
|
||||
};
|
||||
|
||||
static void uc_bpf_buffer_free(void *ptr)
|
||||
{
|
||||
struct uc_bpf_buffer *buf = ptr;
|
||||
|
||||
if (buf->perf)
|
||||
perf_buffer__free(buf->pb);
|
||||
else
|
||||
ring_buffer__free(buf->rb);
|
||||
}
|
||||
|
||||
static const uc_function_list_t buffer_fns[] = {
|
||||
{ "fileno", uc_bpf_buffer_fileno },
|
||||
{ "poll", uc_bpf_buffer_poll },
|
||||
{ "consume", uc_bpf_buffer_consume },
|
||||
};
|
||||
|
||||
static void uc_bpf_fd_free(void *ptr)
|
||||
@@ -805,7 +1309,9 @@ static const uc_function_list_t global_fns[] = {
|
||||
{ "set_debug_handler", uc_bpf_set_debug_handler },
|
||||
{ "open_module", uc_bpf_open_module },
|
||||
{ "open_map", uc_bpf_open_map },
|
||||
{ "open_map_id", uc_bpf_open_map_id },
|
||||
{ "open_program", uc_bpf_open_program },
|
||||
{ "open_program_id", uc_bpf_open_program_id },
|
||||
{ "tc_detach", uc_bpf_tc_detach },
|
||||
};
|
||||
|
||||
@@ -820,5 +1326,6 @@ void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
|
||||
uc_type_declare(vm, "bpf.module", module_fns, module_free);
|
||||
uc_type_declare(vm, "bpf.map", map_fns, uc_bpf_fd_free);
|
||||
uc_type_declare(vm, "bpf.map_iter", map_iter_fns, NULL);
|
||||
uc_type_declare(vm, "bpf.buffer", buffer_fns, uc_bpf_buffer_free);
|
||||
uc_type_declare(vm, "bpf.program", prog_fns, uc_bpf_fd_free);
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=https://github.com/jow-/ucode.git
|
||||
PKG_SOURCE_DATE:=2026-06-03
|
||||
PKG_SOURCE_VERSION:=3ec4e5c238353067e4b58fb9bb9938d85d59e7c2
|
||||
PKG_MIRROR_HASH:=bc0ccef8b34defd524705c73982b39ba9e86fab588e531eba1915eecc57a8351
|
||||
PKG_SOURCE_DATE:=2026-07-09
|
||||
PKG_SOURCE_VERSION:=b885dd0fe1e974551fb1233ca5f3aa74d80b74d9
|
||||
PKG_MIRROR_HASH:=654ba9dc8714aa8caf75ef422962fb465c2b21c8fbe4518a47f9de391cce6e71
|
||||
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
|
||||
PKG_LICENSE:=ISC
|
||||
|
||||
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 6 Jul 2026 18:23:08 +0200
|
||||
Subject: [PATCH] compiler: scope named function expression names to their own
|
||||
body
|
||||
|
||||
A named function expression (e.g. `!function e(){...}()`) shares its parsing
|
||||
path with function declarations, and declared its name in the enclosing scope
|
||||
just as a declaration does. For an expression this is wrong: the name is only
|
||||
meant to be visible inside its own body for self-reference. Binding it in the
|
||||
enclosing scope leaked the name and, by pushing an extra local, shifted the
|
||||
slot count so the initialize_local for a let/const initialised by the
|
||||
expression marked the wrong slot -- the real variable stayed uninitialised and
|
||||
its first use raised "Can't access lexical declaration 'x' before
|
||||
initialization". Self-recursion was likewise broken.
|
||||
|
||||
Bind the name in the enclosing scope only for declarations. For a named
|
||||
expression, rename the function's own callee slot to the name after
|
||||
initialising its compiler, so the body can reference itself while the enclosing
|
||||
scope is left untouched.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/compiler.c
|
||||
+++ b/compiler.c
|
||||
@@ -1949,20 +1949,27 @@ uc_compiler_compile_funcexpr_common(uc_c
|
||||
return;
|
||||
}
|
||||
|
||||
- slot = uc_compiler_resolve_funcstub(compiler, name);
|
||||
+ /* A function declaration binds its name in the enclosing scope. A named
|
||||
+ * function expression must not: its name is only visible inside its own
|
||||
+ * body (for self-reference), and declaring it in the enclosing scope
|
||||
+ * would both leak it and shift the local slots, corrupting the
|
||||
+ * initialisation state of a `let`/`const` the expression initialises. */
|
||||
+ if (require_name) {
|
||||
+ slot = uc_compiler_resolve_funcstub(compiler, name);
|
||||
|
||||
- if (slot > -1) {
|
||||
- compiler->locals.entries[slot].funcstub = false;
|
||||
- }
|
||||
- else {
|
||||
- slot = uc_compiler_declare_local(compiler, name, false);
|
||||
+ if (slot > -1) {
|
||||
+ compiler->locals.entries[slot].funcstub = false;
|
||||
+ }
|
||||
+ else {
|
||||
+ slot = uc_compiler_declare_local(compiler, name, false);
|
||||
|
||||
- if (slot == -1)
|
||||
- uc_compiler_initialize_local(compiler);
|
||||
- else if (compiler->locals.entries[slot].constant)
|
||||
- uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
|
||||
- "Redeclaration of constant '%s'",
|
||||
- ucv_string_get(name));
|
||||
+ if (slot == -1)
|
||||
+ uc_compiler_initialize_local(compiler);
|
||||
+ else if (compiler->locals.entries[slot].constant)
|
||||
+ uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
|
||||
+ "Redeclaration of constant '%s'",
|
||||
+ ucv_string_get(name));
|
||||
+ }
|
||||
}
|
||||
}
|
||||
else if (require_name) {
|
||||
@@ -1976,6 +1983,14 @@ uc_compiler_compile_funcexpr_common(uc_c
|
||||
compiler->program,
|
||||
uc_compiler_is_strict(compiler));
|
||||
|
||||
+ /* Bind a named function expression's name to its own callee slot so the
|
||||
+ * body can reference itself for recursion, without touching the enclosing
|
||||
+ * scope. Declarations keep the name in the enclosing scope (handled above). */
|
||||
+ if (name && !require_name) {
|
||||
+ ucv_put(fncompiler.locals.entries[0].name);
|
||||
+ fncompiler.locals.entries[0].name = ucv_get(name);
|
||||
+ }
|
||||
+
|
||||
fncompiler.parent = compiler;
|
||||
fncompiler.parser = compiler->parser;
|
||||
fncompiler.exprstack = compiler->exprstack;
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Tue, 7 Jul 2026 09:34:16 +0200
|
||||
Subject: [PATCH] lib: avoid allocating print buffer before NULL check in
|
||||
uc_error_message_indent
|
||||
|
||||
Move the print buffer allocation after the guard that returns early on a
|
||||
NULL message, so no buffer is allocated on that path. This keeps the
|
||||
function leak-free when callers invoke it without having produced an error
|
||||
string.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/lib.c
|
||||
+++ b/lib.c
|
||||
@@ -220,13 +220,14 @@ uc_error_context_format(uc_stringbuf_t *
|
||||
|
||||
void
|
||||
uc_error_message_indent(char **msg) {
|
||||
- uc_stringbuf_t *buf = xprintbuf_new();
|
||||
+ uc_stringbuf_t *buf;
|
||||
char *s, *p, *nl;
|
||||
size_t len;
|
||||
|
||||
if (!msg || !*msg)
|
||||
return;
|
||||
|
||||
+ buf = xprintbuf_new();
|
||||
s = *msg;
|
||||
len = strlen(s);
|
||||
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 6 Jul 2026 11:12:32 +0200
|
||||
Subject: [PATCH] compiler: prevent unbounded recompilation on failed
|
||||
module imports
|
||||
|
||||
A source's exports.offset of -1 marks a module whose compilation has been
|
||||
entered but not completed. When a module failed to compile, uc_compiler_finish
|
||||
freed its function and the error cascaded up through the importers via error
|
||||
recovery, leaving each involved source at offset -1 with its function gone. The
|
||||
re-entry guard only recognised an in-progress module by finding its function, so
|
||||
those freed modules were recompiled again on every subsequent import. Across a
|
||||
wide import graph this recompilation multiplies and the compiler appears to hang.
|
||||
|
||||
Detect the offset -1 marker directly instead of relying on the presence of a
|
||||
function: report a circular dependency when the function is still around, and
|
||||
propagate the failure otherwise, rather than recursing into the module again.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/compiler.c
|
||||
+++ b/compiler.c
|
||||
@@ -3479,15 +3479,26 @@ uc_compiler_compile_module_source(uc_com
|
||||
|
||||
uc_program_function_foreach(compiler->program, fn) {
|
||||
if (uc_program_function_source(fn) == source) {
|
||||
- if (source->exports.offset == (size_t)-1)
|
||||
- uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
|
||||
- "Circular dependency");
|
||||
-
|
||||
loaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+ /* An offset of -1 marks a source whose compilation was entered but not yet
|
||||
+ * completed. Re-entering it is either a circular dependency (its function is
|
||||
+ * still present) or a module whose earlier compilation failed and freed its
|
||||
+ * function. Recompiling in either case recurses without bound across a large
|
||||
+ * import graph, so report the cycle and propagate the failure instead. */
|
||||
+ if (source->exports.offset == (size_t)-1) {
|
||||
+ if (loaded)
|
||||
+ uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
|
||||
+ "Circular dependency");
|
||||
+ else if (errp)
|
||||
+ xasprintf(errp, "Module previously failed to compile\n");
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
if (!loaded) {
|
||||
/* We do not yet support linking precompiled modules at compile time,
|
||||
turn static import operation into dynamic load one. */
|
||||
@@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/lib/uloop.c
|
||||
+++ b/lib/uloop.c
|
||||
@@ -1023,7 +1023,22 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
@@ -1028,7 +1028,22 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
|
||||
if (pid == 0) {
|
||||
argp = calloc(ucv_array_length(arguments) + 2, sizeof(char *));
|
||||
@@ -35,7 +35,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
if (!argp || !envp)
|
||||
_exit(-1);
|
||||
@@ -1033,19 +1048,6 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
@@ -1038,19 +1053,6 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
for (i = 0; i < ucv_array_length(arguments); i++)
|
||||
argp[i+1] = ucv_to_string(vm, ucv_array_get(arguments, i));
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/lib/uloop.c
|
||||
+++ b/lib/uloop.c
|
||||
@@ -968,8 +968,9 @@ uc_uloop_process_cb(struct uloop_process
|
||||
@@ -973,8 +973,9 @@ uc_uloop_process_cb(struct uloop_process
|
||||
*
|
||||
* This function creates a process instance for executing external programs.
|
||||
* It takes the executable path string, an optional string array as the argument
|
||||
@@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* @function module:uloop#process
|
||||
*
|
||||
@@ -986,6 +987,11 @@ uc_uloop_process_cb(struct uloop_process
|
||||
@@ -991,6 +992,11 @@ uc_uloop_process_cb(struct uloop_process
|
||||
* @param {Function} callback
|
||||
* The callback function to be invoked when the invoked process ends.
|
||||
*
|
||||
@@ -34,7 +34,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
* @returns {?module:uloop.process}
|
||||
* Returns a process instance for executing external programs.
|
||||
* Returns `null` on error, e.g. due to `exec()` failure or invalid arguments.
|
||||
@@ -995,6 +1001,16 @@ uc_uloop_process_cb(struct uloop_process
|
||||
@@ -1000,6 +1006,16 @@ uc_uloop_process_cb(struct uloop_process
|
||||
* const myProcess = uloop.process("/bin/ls", ["-l", "/tmp"], null, (code) => {
|
||||
* printf(`Process exited with code ${code}\n`);
|
||||
* });
|
||||
@@ -51,7 +51,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
*/
|
||||
static uc_value_t *
|
||||
uc_uloop_process(uc_vm_t *vm, size_t nargs)
|
||||
@@ -1003,6 +1019,7 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
@@ -1008,6 +1024,7 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
uc_value_t *arguments = uc_fn_arg(1);
|
||||
uc_value_t *env_arg = uc_fn_arg(2);
|
||||
uc_value_t *callback = uc_fn_arg(3);
|
||||
@@ -59,7 +59,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
uc_uloop_process_t *process;
|
||||
uc_stringbuf_t *buf;
|
||||
char **argp, **envp;
|
||||
@@ -1012,7 +1029,8 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
@@ -1017,7 +1034,8 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
if (ucv_type(executable) != UC_STRING ||
|
||||
(arguments && ucv_type(arguments) != UC_ARRAY) ||
|
||||
(env_arg && ucv_type(env_arg) != UC_OBJECT) ||
|
||||
@@ -69,7 +69,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
err_return(EINVAL);
|
||||
}
|
||||
|
||||
@@ -1022,6 +1040,13 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
@@ -1027,6 +1045,13 @@ uc_uloop_process(uc_vm_t *vm, size_t nar
|
||||
err_return(errno);
|
||||
|
||||
if (pid == 0) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# Copyright (C) 2015 OpenWrt.org
|
||||
#
|
||||
|
||||
. /lib/functions/uci-defaults.sh
|
||||
|
||||
board_config_update
|
||||
|
||||
board=$(board_name)
|
||||
|
||||
case "$board" in
|
||||
nokia,xg-040g-mf)
|
||||
ucidef_set_led_netdev "lan2" "lan2" "mt7530-0:0a:green:lan-2" "lan2" "link tx rx"
|
||||
ucidef_set_led_netdev "lan3" "lan3" "mt7530-0:0b:green:lan-3" "lan3" "link tx rx"
|
||||
ucidef_set_led_netdev "lan4" "lan4" "mt7530-0:0c:green:lan-4" "lan4" "link tx rx"
|
||||
;;
|
||||
esac
|
||||
|
||||
board_config_flush
|
||||
|
||||
exit 0
|
||||
@@ -14,6 +14,9 @@ an7583_setup_interfaces()
|
||||
airoha,an7583-evb)
|
||||
ucidef_set_interface_lan "lan1 lan2 lan3 lan4 eth1"
|
||||
;;
|
||||
nokia,xg-040g-mf)
|
||||
ucidef_set_interface_lan "lan1 lan2 lan3 lan4"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported hardware. Network interfaces not initialized"
|
||||
;;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
RAMFS_COPY_BIN='fitblk fit_check_sign'
|
||||
|
||||
REQUIRE_IMAGE_METADATA=1
|
||||
|
||||
nokia_initial_setup()
|
||||
{
|
||||
[ "$(rootfs_type)" = "tmpfs" ] || return 0
|
||||
|
||||
fw_setenv bootcmd "flash read 0xc0000 0x800000 0x85000000; bootm 0x85000000"
|
||||
}
|
||||
|
||||
platform_check_image() {
|
||||
local board=$(board_name)
|
||||
|
||||
case "$board" in
|
||||
*)
|
||||
nand_do_platform_check "$board" "$1"
|
||||
return $?
|
||||
;;
|
||||
esac
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
platform_do_upgrade() {
|
||||
local board=$(board_name)
|
||||
|
||||
case "$board" in
|
||||
*)
|
||||
nand_do_upgrade "$1"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
platform_pre_upgrade() {
|
||||
local board=$(board_name)
|
||||
|
||||
case "$board" in
|
||||
nokia,xg-040g-mf)
|
||||
nokia_initial_setup
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
CONFIG_64BIT=y
|
||||
CONFIG_AIROHA_CPU_PM_DOMAIN=y
|
||||
CONFIG_AIROHA_SCU_SSR=y
|
||||
CONFIG_AIROHA_THERMAL=y
|
||||
CONFIG_AIROHA_WATCHDOG=y
|
||||
CONFIG_ARCH_AIROHA=y
|
||||
CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
|
||||
CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
|
||||
CONFIG_ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_FORCE_MAX_ORDER=10
|
||||
@@ -15,41 +12,41 @@ CONFIG_ARCH_MMAP_RND_BITS=18
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MAX=24
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MIN=18
|
||||
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
|
||||
CONFIG_ARCH_PKEY_BITS=3
|
||||
CONFIG_ARCH_PROC_KCORE_TEXT=y
|
||||
CONFIG_ARCH_SPARSEMEM_ENABLE=y
|
||||
CONFIG_ARCH_STACKWALK=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_WANTS_EXECMEM_LATE=y
|
||||
CONFIG_ARCH_WANTS_NO_INSTR=y
|
||||
CONFIG_ARCH_WANTS_THP_SWAP=y
|
||||
CONFIG_ARM64=y
|
||||
CONFIG_ARM64_4K_PAGES=y
|
||||
CONFIG_ARM64_BRBE=y
|
||||
CONFIG_ARM64_ERRATUM_843419=y
|
||||
CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y
|
||||
CONFIG_ARM64_PA_BITS=48
|
||||
CONFIG_ARM64_PA_BITS_48=y
|
||||
CONFIG_ARM64_PLATFORM_DEVICES=y
|
||||
CONFIG_ARM64_TAGGED_ADDR_ABI=y
|
||||
CONFIG_ARM64_VA_BITS=39
|
||||
CONFIG_ARM64_VA_BITS_39=y
|
||||
# CONFIG_ARM64_VA_BITS_48 is not set
|
||||
# CONFIG_ARM64_VA_BITS_52 is not set
|
||||
CONFIG_ARM_AIROHA_SOC_CPUFREQ=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_ARCH_TIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
||||
# CONFIG_ARM_DEBUG_WX is not set
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_GIC_ITS_PARENT=y
|
||||
CONFIG_ARM_GIC_V2M=y
|
||||
CONFIG_ARM_GIC_V3=y
|
||||
CONFIG_ARM_GIC_V3_ITS=y
|
||||
CONFIG_ARM_GIC_V5=y
|
||||
CONFIG_ARM_PMU=y
|
||||
CONFIG_ARM_PMUV3=y
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
CONFIG_ARM_SMCCC_SOC_ID=y
|
||||
# CONFIG_ARM_SMMU is not set
|
||||
# CONFIG_ARM_SMMU_V3 is not set
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
CONFIG_BLK_PM=y
|
||||
CONFIG_BLOCK_NOTIFIERS=y
|
||||
CONFIG_BUFFER_HEAD=y
|
||||
CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC=y
|
||||
CONFIG_CC_HAVE_SHADOW_CALL_STACK=y
|
||||
@@ -59,7 +56,6 @@ CONFIG_COMMON_CLK=y
|
||||
CONFIG_COMMON_CLK_EN7523=y
|
||||
CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
|
||||
# CONFIG_COMPAT_32BIT_TIME is not set
|
||||
# CONFIG_COMPRESSED_INSTALL is not set
|
||||
CONFIG_CONTEXT_TRACKING=y
|
||||
CONFIG_CONTEXT_TRACKING_IDLE=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
@@ -76,31 +72,35 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_STAT=y
|
||||
CONFIG_CPU_LITTLE_ENDIAN=y
|
||||
CONFIG_CPU_MITIGATIONS=y
|
||||
CONFIG_CPU_RMAP=y
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRC32_ARCH=y
|
||||
CONFIG_CRC_CCITT=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_DEFLATE=y
|
||||
CONFIG_CRYPTO_DEV_EIP93=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_HASH_INFO=y
|
||||
CONFIG_CRYPTO_LIB_BLAKE2S_ARCH=y
|
||||
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
|
||||
CONFIG_CRYPTO_LIB_GF128MUL=y
|
||||
CONFIG_CRYPTO_LIB_SHA1=y
|
||||
CONFIG_CRYPTO_LIB_SHA1_ARCH=y
|
||||
CONFIG_CRYPTO_LIB_SHA256_ARCH=y
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
CONFIG_CRYPTO_LZO=y
|
||||
CONFIG_CRYPTO_ZSTD=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_MISC=y
|
||||
CONFIG_DEV_COREDUMP=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y
|
||||
CONFIG_DMA_DIRECT_REMAP=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_NEED_SYNC=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_OPS_HELPERS=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
@@ -111,7 +111,6 @@ CONFIG_FUNCTION_ALIGNMENT=4
|
||||
CONFIG_FUNCTION_ALIGNMENT_4B=y
|
||||
CONFIG_FWNODE_MDIO=y
|
||||
CONFIG_FWNODE_PCS=y
|
||||
CONFIG_FW_CACHE=y
|
||||
# CONFIG_FW_LOADER_USER_HELPER is not set
|
||||
CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y
|
||||
CONFIG_GENERIC_ALLOCATOR=y
|
||||
@@ -129,6 +128,9 @@ CONFIG_GENERIC_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IOREMAP=y
|
||||
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
|
||||
CONFIG_GENERIC_IRQ_ENTRY=y
|
||||
CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD=y
|
||||
CONFIG_GENERIC_IRQ_MIGRATION=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
|
||||
CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
|
||||
@@ -154,16 +156,16 @@ CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=y
|
||||
CONFIG_HAS_IOPORT_MAP=y
|
||||
# CONFIG_HISILICON_ERRATUM_162100801 is not set
|
||||
CONFIG_HOTPLUG_CORE_SYNC=y
|
||||
CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_HOTPLUG_SMT=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_AIROHA=y
|
||||
# CONFIG_IDPF is not set
|
||||
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
CONFIG_IO_URING=y
|
||||
CONFIG_IPC_NS=y
|
||||
CONFIG_IO_URING_ZCRX=y
|
||||
CONFIG_IPV6=y
|
||||
CONFIG_IPV6_MULTIPLE_TABLES=y
|
||||
# CONFIG_IPV6_SUBTREES is not set
|
||||
@@ -180,6 +182,7 @@ CONFIG_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_MSI_IOMMU=y
|
||||
CONFIG_IRQ_MSI_LIB=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_JBD2=y
|
||||
@@ -191,15 +194,13 @@ CONFIG_LZO_COMPRESS=y
|
||||
CONFIG_LZO_DECOMPRESS=y
|
||||
CONFIG_MDIO_AIROHA=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MDIO_DEVRES=y
|
||||
# CONFIG_MEDIATEK_GE_SOC_PHY is not set
|
||||
# CONFIG_MEMCG is not set
|
||||
CONFIG_MEDIATEK_GE_SOC_PHY=y
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MIGRATION=y
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_BLOCK=y
|
||||
CONFIG_MMC_CQHCI=y
|
||||
CONFIG_MMC_HSQ=y
|
||||
CONFIG_MMC_MTK=y
|
||||
CONFIG_MMU_LAZY_TLB_REFCOUNT=y
|
||||
CONFIG_MODULES_TREE_LOOKUP=y
|
||||
@@ -215,6 +216,8 @@ CONFIG_MTD_UBI=y
|
||||
CONFIG_MTD_UBI_BEB_LIMIT=20
|
||||
CONFIG_MTD_UBI_BLOCK=y
|
||||
CONFIG_MTD_UBI_WL_THRESHOLD=4096
|
||||
CONFIG_MTD_VIRT_CONCAT=y
|
||||
CONFIG_MTK_NET_PHYLIB=y
|
||||
CONFIG_MUTEX_SPIN_ON_OWNER=y
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEED_SG_DMA_LENGTH=y
|
||||
@@ -224,15 +227,17 @@ CONFIG_NET_AIROHA_NPU=y
|
||||
CONFIG_NET_DEVLINK=y
|
||||
CONFIG_NET_DSA=y
|
||||
CONFIG_NET_DSA_MT7530=y
|
||||
CONFIG_NET_DSA_MT7530_MDIO=y
|
||||
# CONFIG_NET_DSA_MT7530_MDIO is not set
|
||||
CONFIG_NET_DSA_MT7530_MMIO=y
|
||||
CONFIG_NET_DSA_TAG_MTK=y
|
||||
CONFIG_NET_EGRESS=y
|
||||
CONFIG_NET_FLOW_LIMIT=y
|
||||
# CONFIG_NET_MEDIATEK_SOC is not set
|
||||
CONFIG_NET_INGRESS=y
|
||||
CONFIG_NET_SELFTESTS=y
|
||||
# CONFIG_NET_VENDOR_3COM is not set
|
||||
CONFIG_NET_VENDOR_AIROHA=y
|
||||
# CONFIG_NET_VENDOR_MEDIATEK is not set
|
||||
CONFIG_NET_XGRESS=y
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
@@ -250,6 +255,7 @@ CONFIG_OF_GPIO=y
|
||||
CONFIG_OF_IRQ=y
|
||||
CONFIG_OF_KOBJ=y
|
||||
CONFIG_OF_MDIO=y
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PAGE_BLOCK_MAX_ORDER=10
|
||||
CONFIG_PAGE_POOL=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
|
||||
@@ -269,6 +275,7 @@ CONFIG_PCIE_PME=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PCS_AIROHA=y
|
||||
# CONFIG_PCS_AIROHA_AN7581 is not set
|
||||
CONFIG_PCS_AIROHA_AN7583=y
|
||||
CONFIG_PERF_EVENTS=y
|
||||
@@ -280,6 +287,7 @@ CONFIG_PHYLINK=y
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_PHY_AIROHA_PCIE=y
|
||||
# CONFIG_PHY_AIROHA_USB is not set
|
||||
CONFIG_PHY_PACKAGE=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_AIROHA=y
|
||||
# CONFIG_PINCTRL_MT2712 is not set
|
||||
@@ -308,13 +316,13 @@ CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RAS=y
|
||||
CONFIG_RATIONAL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_IRQ=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_RELOCATABLE=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_SECCOMP=y
|
||||
@@ -327,8 +335,8 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=5
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SGL_ALLOC=y
|
||||
CONFIG_SMP=y
|
||||
# CONFIG_SND_SOC_AN7581 is not set
|
||||
CONFIG_SOCK_RX_QUEUE_MAPPING=y
|
||||
CONFIG_SOC_BUS=y
|
||||
CONFIG_SOFTIRQ_ON_OWN_STACK=y
|
||||
@@ -338,14 +346,14 @@ CONFIG_SPARSEMEM_VMEMMAP=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SPI=y
|
||||
# CONFIG_SPI_AIROHA_EN7523 is not set
|
||||
CONFIG_SPI_AIROHA_SNFI=y
|
||||
CONFIG_SPI_MASTER=y
|
||||
CONFIG_SPI_MEM=y
|
||||
CONFIG_SPLIT_PMD_PTLOCKS=y
|
||||
CONFIG_SPLIT_PTE_PTLOCKS=y
|
||||
CONFIG_SWIOTLB=y
|
||||
CONFIG_SWPHY=y
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
# CONFIG_TEST_FPU is not set
|
||||
CONFIG_THERMAL=y
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
@@ -363,6 +371,7 @@ CONFIG_UBIFS_FS=y
|
||||
CONFIG_USER_STACKTRACE_SUPPORT=y
|
||||
CONFIG_VDSO_GETRANDOM=y
|
||||
CONFIG_VMAP_STACK=y
|
||||
CONFIG_WANT_DEV_COREDUMP=y
|
||||
CONFIG_WATCHDOG_CORE=y
|
||||
# CONFIG_WLAN is not set
|
||||
# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
|
||||
|
||||
@@ -3,7 +3,11 @@ SUBTARGET:=an7583
|
||||
BOARDNAME:=AN7583
|
||||
CPU_TYPE:=cortex-a53
|
||||
KERNELNAME:=Image dtbs
|
||||
FEATURES+=pwm source-only
|
||||
FEATURES+=pwm
|
||||
|
||||
DEFAULT_PACKAGES += \
|
||||
airoha-an7583-npu-firmware kmod-leds-gpio \
|
||||
kmod-gpio-button-hotplug uboot-envtools
|
||||
|
||||
define Target/Description
|
||||
Build firmware images for Airoha an7583 ARM based boards.
|
||||
|
||||
@@ -5,26 +5,9 @@
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include "an7581.dtsi"
|
||||
#include "an758x-nokia_xg-040g-common.dtsi"
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
label-mac-device = &gdm1;
|
||||
|
||||
led-boot = &led_power_green;
|
||||
led-failsafe = &led_power_green;
|
||||
led-running = &led_power_green;
|
||||
led-upgrade = &led_power_green;
|
||||
|
||||
serial0 = &uart1;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200 earlycon";
|
||||
stdout-path = "serial0:115200n8";
|
||||
linux,usable-memory-range =
|
||||
<0x0 0x80200000 0x0 0x1fe00000>;
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
@@ -83,11 +66,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x80000000 0x0 0x20000000>;
|
||||
};
|
||||
|
||||
reg_3p3v: regulator-3p3v {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-always-on;
|
||||
@@ -153,18 +131,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
ð {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ð_pcs {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mdio {
|
||||
/* Airoha EN8811 2.5Gbps phy */
|
||||
en8811: ethernet-phy@f {
|
||||
@@ -190,44 +156,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
&npu {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pon_pcs {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&snfi {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/*
|
||||
* SkyHigh ML02G300WHI00
|
||||
*/
|
||||
&spi_nand {
|
||||
/*
|
||||
* ECC must be aligned with bootloader to prevent read errors.
|
||||
* Stock fw also uses NAND_ECC_NONE.
|
||||
*/
|
||||
nand-ecc-mode = "none";
|
||||
nand-ecc-step-size = <2048>;
|
||||
nand-ecc-strength = <0>;
|
||||
|
||||
partitions: partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
&gdm1 {
|
||||
status = "okay";
|
||||
|
||||
nvmem-cell-names = "mac-address";
|
||||
nvmem-cells = <&macaddr_factory_3e (0)>;
|
||||
};
|
||||
|
||||
&switch {
|
||||
status = "okay";
|
||||
|
||||
|
||||
@@ -1,84 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
|
||||
#include "an7581-nokia_xg-040g-md-common.dtsi"
|
||||
#include "an758x-nokia_xg-040g-ubi-parts.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Nokia XG-040G-MD (UBI)";
|
||||
compatible = "nokia,xg-040g-md-ubi", "airoha,an7581",
|
||||
"airoha,en7581";
|
||||
|
||||
chosen {
|
||||
rootdisk = <&ubi_fit>;
|
||||
};
|
||||
};
|
||||
|
||||
&partitions {
|
||||
partition@0_all {
|
||||
label = "all_flash";
|
||||
reg = <0x0 0x10000000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@0 {
|
||||
label = "bl2";
|
||||
reg = <0x0 0x20000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@20000 {
|
||||
label = "ubi";
|
||||
reg = <0x20000 0xffe0000>;
|
||||
compatible = "linux,ubi";
|
||||
|
||||
volumes {
|
||||
ubi-volume-bosa {
|
||||
volname = "bosa";
|
||||
};
|
||||
|
||||
ubi-volume-factory {
|
||||
volname = "ri";
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "fixed-layout";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_factory_3e: macaddr@3e {
|
||||
compatible = "mac-base";
|
||||
reg = <0x3e 0x6>;
|
||||
#nvmem-cell-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ubi_fit: ubi-volume-fit {
|
||||
volname = "fit";
|
||||
};
|
||||
|
||||
ubi-volume-fip {
|
||||
volname = "fip";
|
||||
};
|
||||
|
||||
ubi_env: ubi-volume-ubootenv {
|
||||
volname = "ubootenv";
|
||||
};
|
||||
|
||||
ubi_env2: ubi-volume-ubootenv2 {
|
||||
volname = "ubootenv2";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ubi_env {
|
||||
nvmem-layout {
|
||||
compatible = "u-boot,env-redundant-bool-layout";
|
||||
};
|
||||
};
|
||||
|
||||
&ubi_env2 {
|
||||
nvmem-layout {
|
||||
compatible = "u-boot,env-redundant-bool-layout";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,152 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
|
||||
#include "an7581-nokia_xg-040g-md-common.dtsi"
|
||||
#include "an758x-nokia_xg-040g-stock-parts.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Nokia XG-040G-MD";
|
||||
compatible = "nokia,xg-040g-md", "airoha,an7581", "airoha,en7581";
|
||||
|
||||
virtual_flash {
|
||||
compatible = "mtd-concat";
|
||||
devices = <&ubi4 &ubi1 &ubi2 &ubi3 &ubi5 &ubi6>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "ubi";
|
||||
reg = <0x0 0x0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&partitions {
|
||||
partition@0_all {
|
||||
label = "all_flash";
|
||||
reg = <0x0 0xeba0000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@0 {
|
||||
label = "bootloader";
|
||||
reg = <0x0 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@60000 {
|
||||
label = "u-boot-env";
|
||||
reg = <0x60000 0x20000>;
|
||||
};
|
||||
|
||||
partition@80000 {
|
||||
label = "romfile";
|
||||
reg = <0x80000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@c0000 {
|
||||
label = "nsb_1";
|
||||
reg = <0xc0000 0x2880000>;
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "kernel";
|
||||
reg = <0x0 0x800000>;
|
||||
};
|
||||
|
||||
ubi1: partition@800000 {
|
||||
label = "rootfs_1";
|
||||
reg = <0x800000 0x2080000>;
|
||||
};
|
||||
};
|
||||
|
||||
ubi2: partition@2940000 {
|
||||
label = "nsb_2";
|
||||
reg = <0x2940000 0x2880000>;
|
||||
};
|
||||
|
||||
partition@51c0000 {
|
||||
label = "bosa";
|
||||
reg = <0x51c0000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@5200000 {
|
||||
label = "ri";
|
||||
reg = <0x5200000 0x40000>;
|
||||
read-only;
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "fixed-layout";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_factory_3e: macaddr@3e {
|
||||
compatible = "mac-base";
|
||||
reg = <0x3e 0x6>;
|
||||
#nvmem-cell-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
partition@5240000 {
|
||||
label = "flag";
|
||||
reg = <0x5240000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@5280000 {
|
||||
label = "flagback";
|
||||
reg = <0x5280000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
ubi3: partition@52c0000 {
|
||||
label = "config";
|
||||
reg = <0x52c0000 0xa00000>;
|
||||
};
|
||||
|
||||
ubi4: partition@5cc0000 {
|
||||
label = "data";
|
||||
reg = <0x5cc0000 0x80e0000>;
|
||||
};
|
||||
|
||||
ubi5: partition@dda0000 {
|
||||
label = "oopsfs";
|
||||
reg = <0xdda0000 0x400000>;
|
||||
};
|
||||
|
||||
partition@e1a0000 {
|
||||
label = "log";
|
||||
reg = <0xe1a0000 0xa00000>;
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
ubi6: partition@0 {
|
||||
label = "log_truncated";
|
||||
reg = <0x0 0x9c0000>;
|
||||
};
|
||||
|
||||
/*
|
||||
* Must be excluded from ubi. Otherwise the data
|
||||
* will be broken after U-Boot 'bootflag swap'
|
||||
* command call. This command writes bootflag at
|
||||
* 0xeb60000 (boot_flag_addr).
|
||||
*/
|
||||
partition@9c0000 {
|
||||
label = "bootflag";
|
||||
reg = <0x9c0000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
|
||||
/dts-v1/;
|
||||
#include <dt-bindings/leds/common.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include "an7583.dtsi"
|
||||
#include "an758x-nokia_xg-040g-common.dtsi"
|
||||
|
||||
/ {
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
button-0 {
|
||||
label = "reset";
|
||||
linux,code = <KEY_RESTART>;
|
||||
gpios = <&an7583_pinctrl 0 GPIO_ACTIVE_LOW>;
|
||||
debounce-interval = <60>;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led-0 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_WAN;
|
||||
gpios = <&an7583_pinctrl 6 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led-1 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_WAN_ONLINE;
|
||||
gpios = <&an7583_pinctrl 7 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led_power_green: led-2 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_POWER;
|
||||
gpios = <&an7583_pinctrl 25 GPIO_ACTIVE_LOW>;
|
||||
panic-indicator;
|
||||
};
|
||||
|
||||
led-3 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_USB;
|
||||
function-enumerator = <1>;
|
||||
gpios = <&an7583_pinctrl 26 GPIO_ACTIVE_LOW>;
|
||||
/*
|
||||
* AN7583 SoC doesn't support USB at this time
|
||||
*
|
||||
* linux,default-trigger = "usbport";
|
||||
* trigger-sources = <&usb_port1>;
|
||||
*/
|
||||
};
|
||||
|
||||
led-4 {
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
function = LED_FUNCTION_WAN;
|
||||
gpios = <&an7583_pinctrl 27 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led-5 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_USB;
|
||||
function-enumerator = <2>;
|
||||
gpios = <&an7583_pinctrl 33 GPIO_ACTIVE_LOW>;
|
||||
/*
|
||||
* AN7583 SoC doesn't support USB at this time
|
||||
*
|
||||
* linux,default-trigger = "usbport";
|
||||
* trigger-sources = <&usb_port2>;
|
||||
*/
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* AN7583 SoC doesn't support USB at this time
|
||||
*
|
||||
* reg_3p3v: regulator-3p3v {
|
||||
* compatible = "regulator-fixed";
|
||||
* regulator-always-on;
|
||||
* regulator-boot-on;
|
||||
* regulator-max-microvolt = <3300000>;
|
||||
* regulator-min-microvolt = <3300000>;
|
||||
* regulator-name = "fixed-3.3V";
|
||||
* };
|
||||
*
|
||||
* reg_usb_5v: regulator-usb-5v {
|
||||
* compatible = "regulator-fixed";
|
||||
* enable-active-high;
|
||||
* gpio = <&an7583_pinctrl 30 GPIO_ACTIVE_HIGH>;
|
||||
* regulator-boot-on;
|
||||
* regulator-max-microvolt = <5000000>;
|
||||
* regulator-min-microvolt = <5000000>;
|
||||
* regulator-name = "usb-5v";
|
||||
* };
|
||||
*
|
||||
* *
|
||||
* * Controls both USB ports at once
|
||||
* *
|
||||
* usb-power {
|
||||
* compatible = "regulator-output";
|
||||
* vout-supply = <®_usb_5v>;
|
||||
* };
|
||||
*/
|
||||
};
|
||||
|
||||
&an7583_pinctrl {
|
||||
gpio-ranges = <&an7583_pinctrl 0 2 53>;
|
||||
|
||||
mdio0_pins: mdio0-pins {
|
||||
conf {
|
||||
pins = "mdio_0";
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
|
||||
pcie0_rst_pins: pcie0-rst-pins {
|
||||
conf {
|
||||
pins = "pcie_reset0";
|
||||
drive-open-drain = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
pcie1_rst_pins: pcie1-rst-pins {
|
||||
conf {
|
||||
pins = "pcie_reset1";
|
||||
drive-open-drain = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
gswp1_led0_pins: gswp1-led0-pins {
|
||||
mux {
|
||||
function = "phy1_led0";
|
||||
pins = "gpio1";
|
||||
};
|
||||
};
|
||||
|
||||
gswp2_led0_pins: gswp2-led0-pins {
|
||||
mux {
|
||||
function = "phy2_led0";
|
||||
pins = "gpio2";
|
||||
};
|
||||
};
|
||||
|
||||
gswp3_led0_pins: gswp3-led0-pins {
|
||||
mux {
|
||||
function = "phy3_led0";
|
||||
pins = "gpio3";
|
||||
};
|
||||
};
|
||||
|
||||
gswp4_led0_pins: gswp4-led0-pins {
|
||||
mux {
|
||||
function = "phy4_led0";
|
||||
pins = "gpio4";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&mdio_0 {
|
||||
/* Airoha EN8811 2.5Gbps phy */
|
||||
en8811: ethernet-phy@f {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <0xf>;
|
||||
|
||||
reset-gpios = <&an7583_pinctrl 34 GPIO_ACTIVE_LOW>;
|
||||
reset-assert-us = <10000>;
|
||||
reset-deassert-us = <20000>;
|
||||
|
||||
leds {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led-0 {
|
||||
reg = <0>;
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <1>;
|
||||
default-state = "keep";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&switch {
|
||||
status = "okay";
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&mdio0_pins>;
|
||||
};
|
||||
|
||||
&gsw_port1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&gsw_phy1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&gsw_phy2 {
|
||||
interrupts = <2>;
|
||||
|
||||
pinctrl-names = "gbe-led";
|
||||
pinctrl-0 = <&gswp2_led0_pins>;
|
||||
};
|
||||
|
||||
&gsw_phy2_led0 {
|
||||
status = "okay";
|
||||
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
active-low;
|
||||
};
|
||||
|
||||
&gsw_phy3 {
|
||||
interrupts = <3>;
|
||||
|
||||
pinctrl-names = "gbe-led";
|
||||
pinctrl-0 = <&gswp3_led0_pins>;
|
||||
};
|
||||
|
||||
&gsw_phy3_led0 {
|
||||
status = "okay";
|
||||
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
active-low;
|
||||
};
|
||||
|
||||
&gsw_phy4 {
|
||||
interrupts = <4>;
|
||||
|
||||
pinctrl-names = "gbe-led";
|
||||
pinctrl-0 = <&gswp4_led0_pins>;
|
||||
};
|
||||
|
||||
&gsw_phy4_led0 {
|
||||
status = "okay";
|
||||
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
active-low;
|
||||
};
|
||||
|
||||
&gdm3 {
|
||||
status = "okay";
|
||||
|
||||
openwrt,netdev-name = "lan1";
|
||||
|
||||
phy-handle = <&en8811>;
|
||||
phy-mode = "2500base-x";
|
||||
|
||||
nvmem-cell-names = "mac-address";
|
||||
nvmem-cells = <&macaddr_factory_3e (0)>;
|
||||
};
|
||||
|
||||
/*
|
||||
* AN7583 SoC doesn't support USB at this time
|
||||
*
|
||||
* &usb0 {
|
||||
* status = "okay";
|
||||
* #address-cells = <1>;
|
||||
* #size-cells = <0>;
|
||||
*
|
||||
* vusb33-supply = <®_3p3v>;
|
||||
*
|
||||
* usb_port1: port@1 {
|
||||
* reg = <1>;
|
||||
* #trigger-source-cells = <0>;
|
||||
* };
|
||||
*
|
||||
* usb_port2: port@2 {
|
||||
* reg = <2>;
|
||||
* #trigger-source-cells = <0>;
|
||||
* };
|
||||
* };
|
||||
*/
|
||||
@@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
|
||||
#include "an7583-nokia_xg-040g-mf-common.dtsi"
|
||||
#include "an758x-nokia_xg-040g-stock-parts.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Nokia XG-040G-MF";
|
||||
compatible = "nokia,xg-040g-mf", "airoha,an7583", "airoha,en7583";
|
||||
};
|
||||
@@ -412,7 +412,7 @@
|
||||
};
|
||||
|
||||
i2c0: i2c0@1fbf8000 {
|
||||
compatible = "airoha,an7581-i2c";
|
||||
compatible = "mediatek,mt7621-i2c";
|
||||
reg = <0x0 0x1fbf8000 0x0 0x100>;
|
||||
|
||||
clocks = <&i2cclock>;
|
||||
@@ -426,7 +426,7 @@
|
||||
};
|
||||
|
||||
i2c1: i2c1@1fbf8100 {
|
||||
compatible = "airoha,an7581-i2c";
|
||||
compatible = "mediatek,mt7621-i2c";
|
||||
reg = <0x0 0x1fbf8100 0x0 0x100>;
|
||||
|
||||
clocks = <&i2cclock>;
|
||||
@@ -671,7 +671,7 @@
|
||||
gdm2: ethernet@2 {
|
||||
compatible = "airoha,eth-mac";
|
||||
reg = <2>;
|
||||
pcs = <&pon_pcs>;
|
||||
pcs-handle = <&pon_pcs>;
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -679,7 +679,7 @@
|
||||
gdm3: ethernet@3 {
|
||||
compatible = "airoha,eth-mac";
|
||||
reg = <3>;
|
||||
pcs = <ð_pcs>;
|
||||
pcs-handle = <ð_pcs>;
|
||||
airoha,gdm-srcport = <0x16>;
|
||||
|
||||
status = "disabled";
|
||||
@@ -760,15 +760,26 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/*
|
||||
* Board DTS files enabling these nodes
|
||||
* must provide the 'color' property.
|
||||
* If a board implements multiple
|
||||
* identical colors,
|
||||
* 'function-enumerator' values must be
|
||||
* overridden to maintain unique sysfs
|
||||
* naming.
|
||||
*/
|
||||
gsw_phy1_led0: gsw-phy1-led0@0 {
|
||||
reg = <0>;
|
||||
function = "phy1_led0";
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gsw_phy1_led1: gsw-phy1-led1@1 {
|
||||
reg = <1>;
|
||||
function = "phy1_led1";
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
@@ -785,13 +796,15 @@
|
||||
|
||||
gsw_phy2_led0: gsw-phy2-led0@0 {
|
||||
reg = <0>;
|
||||
function = "phy2_led0";
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gsw_phy2_led1: gsw-phy2-led1@1 {
|
||||
reg = <1>;
|
||||
function = "phy1_led1";
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
@@ -809,12 +822,14 @@
|
||||
gsw_phy3_led0: gsw-phy3-led0@0 {
|
||||
reg = <0>;
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gsw_phy3_led1: gsw-phy3-led1@1 {
|
||||
reg = <1>;
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
@@ -832,12 +847,14 @@
|
||||
gsw_phy4_led0: gsw-phy4-led0@0 {
|
||||
reg = <0>;
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <4>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gsw_phy4_led1: gsw-phy4-led1@1 {
|
||||
reg = <1>;
|
||||
function = LED_FUNCTION_LAN;
|
||||
function-enumerator = <4>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
label-mac-device = &gdm1;
|
||||
|
||||
led-boot = &led_power_green;
|
||||
led-failsafe = &led_power_green;
|
||||
led-running = &led_power_green;
|
||||
led-upgrade = &led_power_green;
|
||||
|
||||
serial0 = &uart1;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200 earlycon";
|
||||
stdout-path = "serial0:115200n8";
|
||||
linux,usable-memory-range =
|
||||
<0x0 0x80200000 0x0 0x1fe00000>;
|
||||
};
|
||||
|
||||
memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x80000000 0x0 0x20000000>;
|
||||
};
|
||||
};
|
||||
|
||||
ð {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ð_pcs {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&npu {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pon_pcs {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&snfi {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi_nand {
|
||||
/*
|
||||
* ECC must be aligned with bootloader to prevent read errors.
|
||||
* Stock fw also uses NAND_ECC_NONE.
|
||||
*/
|
||||
nand-ecc-mode = "none";
|
||||
nand-ecc-step-size = <2048>;
|
||||
nand-ecc-strength = <0>;
|
||||
|
||||
partitions: partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
&gdm1 {
|
||||
status = "okay";
|
||||
|
||||
nvmem-cell-names = "mac-address";
|
||||
nvmem-cells = <&macaddr_factory_3e (0)>;
|
||||
};
|
||||
@@ -0,0 +1,147 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
|
||||
/ {
|
||||
virtual_flash {
|
||||
compatible = "mtd-concat";
|
||||
devices = <&ubi4 &ubi1 &ubi2 &ubi3 &ubi5 &ubi6>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "ubi";
|
||||
reg = <0x0 0x0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&partitions {
|
||||
partition@0_all {
|
||||
label = "all_flash";
|
||||
reg = <0x0 0xeba0000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@0 {
|
||||
label = "bootloader";
|
||||
reg = <0x0 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@60000 {
|
||||
label = "u-boot-env";
|
||||
reg = <0x60000 0x20000>;
|
||||
};
|
||||
|
||||
partition@80000 {
|
||||
label = "romfile";
|
||||
reg = <0x80000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@c0000 {
|
||||
label = "nsb_1";
|
||||
reg = <0xc0000 0x2880000>;
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "kernel";
|
||||
reg = <0x0 0x800000>;
|
||||
};
|
||||
|
||||
ubi1: partition@800000 {
|
||||
label = "rootfs_1";
|
||||
reg = <0x800000 0x2080000>;
|
||||
};
|
||||
};
|
||||
|
||||
ubi2: partition@2940000 {
|
||||
label = "nsb_2";
|
||||
reg = <0x2940000 0x2880000>;
|
||||
};
|
||||
|
||||
partition@51c0000 {
|
||||
label = "bosa";
|
||||
reg = <0x51c0000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@5200000 {
|
||||
label = "ri";
|
||||
reg = <0x5200000 0x40000>;
|
||||
read-only;
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "fixed-layout";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_factory_3e: macaddr@3e {
|
||||
compatible = "mac-base";
|
||||
reg = <0x3e 0x6>;
|
||||
#nvmem-cell-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
partition@5240000 {
|
||||
label = "flag";
|
||||
reg = <0x5240000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@5280000 {
|
||||
label = "flagback";
|
||||
reg = <0x5280000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
ubi3: partition@52c0000 {
|
||||
label = "config";
|
||||
reg = <0x52c0000 0xa00000>;
|
||||
};
|
||||
|
||||
ubi4: partition@5cc0000 {
|
||||
label = "data";
|
||||
reg = <0x5cc0000 0x80e0000>;
|
||||
};
|
||||
|
||||
ubi5: partition@dda0000 {
|
||||
label = "oopsfs";
|
||||
reg = <0xdda0000 0x400000>;
|
||||
};
|
||||
|
||||
partition@e1a0000 {
|
||||
label = "log";
|
||||
reg = <0xe1a0000 0xa00000>;
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
ubi6: partition@0 {
|
||||
label = "log_truncated";
|
||||
reg = <0x0 0x9c0000>;
|
||||
};
|
||||
|
||||
/*
|
||||
* Must be excluded from ubi. Otherwise the data
|
||||
* will be broken after U-Boot 'bootflag swap'
|
||||
* command call. This command writes bootflag at
|
||||
* 0xeb60000 (boot_flag_addr).
|
||||
*/
|
||||
partition@9c0000 {
|
||||
label = "bootflag";
|
||||
reg = <0x9c0000 0x40000>;
|
||||
read-only;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
rootdisk = <&ubi_fit>;
|
||||
};
|
||||
};
|
||||
|
||||
&partitions {
|
||||
partition@0_all {
|
||||
label = "all_flash";
|
||||
reg = <0x0 0x10000000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@0 {
|
||||
label = "bl2";
|
||||
reg = <0x0 0x20000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@20000 {
|
||||
label = "ubi";
|
||||
reg = <0x20000 0xffe0000>;
|
||||
compatible = "linux,ubi";
|
||||
|
||||
volumes {
|
||||
ubi-volume-bosa {
|
||||
volname = "bosa";
|
||||
};
|
||||
|
||||
ubi-volume-factory {
|
||||
volname = "ri";
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "fixed-layout";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_factory_3e: macaddr@3e {
|
||||
compatible = "mac-base";
|
||||
reg = <0x3e 0x6>;
|
||||
#nvmem-cell-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ubi_fit: ubi-volume-fit {
|
||||
volname = "fit";
|
||||
};
|
||||
|
||||
ubi-volume-fip {
|
||||
volname = "fip";
|
||||
};
|
||||
|
||||
ubi_env: ubi-volume-ubootenv {
|
||||
volname = "ubootenv";
|
||||
};
|
||||
|
||||
ubi_env2: ubi-volume-ubootenv2 {
|
||||
volname = "ubootenv2";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ubi_env {
|
||||
nvmem-layout {
|
||||
compatible = "u-boot,env-redundant-bool-layout";
|
||||
};
|
||||
};
|
||||
|
||||
&ubi_env2 {
|
||||
nvmem-layout {
|
||||
compatible = "u-boot,env-redundant-bool-layout";
|
||||
};
|
||||
};
|
||||
@@ -1,17 +1,20 @@
|
||||
define Device/FitImageLzma
|
||||
KERNEL_SUFFIX := -uImage.itb
|
||||
KERNEL = kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
|
||||
KERNEL_NAME := Image
|
||||
KERNEL_SUFFIX := -uImage.itb
|
||||
KERNEL = kernel-bin | lzma | \
|
||||
fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
|
||||
KERNEL_NAME := Image
|
||||
endef
|
||||
|
||||
define Device/airoha_an7583-evb
|
||||
$(call Device/FitImageLzma)
|
||||
DEVICE_VENDOR := Airoha
|
||||
DEVICE_MODEL := AN7583 Evaluation Board (SNAND)
|
||||
DEVICE_PACKAGES := kmod-phy-aeonsemi-as21xxx kmod-leds-pwm kmod-pwm-airoha kmod-input-gpio-keys-polled
|
||||
DEVICE_PACKAGES := kmod-phy-aeonsemi-as21xxx kmod-leds-pwm \
|
||||
kmod-pwm-airoha kmod-input-gpio-keys-polled
|
||||
DEVICE_DTS := an7583-evb
|
||||
DEVICE_DTS_CONFIG := config@1
|
||||
IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | pad-rootfs | append-metadata
|
||||
IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | \
|
||||
pad-rootfs | append-metadata
|
||||
endef
|
||||
TARGET_DEVICES += airoha_an7583-evb
|
||||
|
||||
@@ -22,3 +25,22 @@ define Device/airoha_an7583-evb-emmc
|
||||
DEVICE_PACKAGES := kmod-phy-airoha-en8811h kmod-i2c-an7581
|
||||
endef
|
||||
TARGET_DEVICES += airoha_an7583-evb-emmc
|
||||
|
||||
define Device/nokia_xg-040g-mf
|
||||
$(call Device/FitImageLzma)
|
||||
DEVICE_VENDOR := Nokia
|
||||
DEVICE_MODEL := XG-040G-MF
|
||||
DEVICE_DTS := an7583-nokia_xg-040g-mf
|
||||
DEVICE_DTS_CONFIG := config@1
|
||||
BLOCKSIZE := 128k
|
||||
PAGESIZE := 2048
|
||||
UBINIZE_OPTS := -E 5
|
||||
IMAGE_SIZE := 131968k
|
||||
KERNEL_SIZE := 8192k
|
||||
IMAGES += factory-kernel.bin factory-rootfs.bin
|
||||
IMAGE/factory-kernel.bin := append-kernel
|
||||
IMAGE/factory-rootfs.bin := append-ubi | check-size
|
||||
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
|
||||
DEVICE_PACKAGES := kmod-phy-airoha-en8811h
|
||||
endef
|
||||
TARGET_DEVICES += nokia_xg-040g-mf
|
||||
|
||||
@@ -9,8 +9,7 @@ define KernelPackage/i2c-an7581
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
$(call i2c_defaults,$(I2C_MT7621_MODULES),79)
|
||||
TITLE:=Airoha I2C Controller
|
||||
DEPENDS:=+kmod-i2c-core \
|
||||
@(TARGET_airoha_an7581)
|
||||
DEPENDS:=+kmod-i2c-core @TARGET_airoha
|
||||
endef
|
||||
|
||||
define KernelPackage/i2c-an7581/description
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
From: Robert Marko <robert.marko@sartura.hr>
|
||||
Date: Thu, 16 Jul 2026 14:00:00 +0200
|
||||
Subject: [PATCH] net: pcs: airoha: fix AN7583 PCS port count
|
||||
|
||||
The AN7583 PCS match data does not initialize num_port. This leaves it at
|
||||
zero, so probe allocates a zero-sized ports array and a later PCS lookup
|
||||
returns a pointer derived from NULL.
|
||||
|
||||
Set the number of ports for each AN7583 PCS instance. Also reject
|
||||
out-of-range PCS indices defensively.
|
||||
|
||||
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
|
||||
---
|
||||
drivers/net/pcs/airoha/pcs-airoha-common.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/net/pcs/airoha/pcs-airoha-common.c
|
||||
+++ b/drivers/net/pcs/airoha/pcs-airoha-common.c
|
||||
@@ -1170,6 +1170,10 @@ static struct phylink_pcs *airoha_pcs_ge
|
||||
if (pcsspec->nargs)
|
||||
index = pcsspec->args[0];
|
||||
|
||||
+ if (index >= priv->data->num_port)
|
||||
+ return dev_err_ptr_probe(dev, -EINVAL,
|
||||
+ "invalid PCS index %d\n", index);
|
||||
+
|
||||
return &priv->ports[index].pcs;
|
||||
}
|
||||
|
||||
@@ -1418,6 +1422,7 @@ static const struct airoha_pcs_match_dat
|
||||
};
|
||||
|
||||
static const struct airoha_pcs_match_data an7583_pcs_eth = {
|
||||
+ .num_port = 1,
|
||||
.port_type = AIROHA_PCS_ETH,
|
||||
.usxgmii_rx_gb_out_vld_tweak = true,
|
||||
.usxgmii_xfi_mode_sel = true,
|
||||
@@ -1426,6 +1431,7 @@ static const struct airoha_pcs_match_dat
|
||||
};
|
||||
|
||||
static const struct airoha_pcs_match_data an7583_pcs_pon = {
|
||||
+ .num_port = 1,
|
||||
.port_type = AIROHA_PCS_PON,
|
||||
.usxgmii_rx_gb_out_vld_tweak = true,
|
||||
.usxgmii_xfi_mode_sel = true,
|
||||
@@ -1434,6 +1440,7 @@ static const struct airoha_pcs_match_dat
|
||||
};
|
||||
|
||||
static const struct airoha_pcs_match_data an7583_pcs_pcie = {
|
||||
+ .num_port = 2,
|
||||
.port_type = AIROHA_PCS_PCIE,
|
||||
.usxgmii_rx_gb_out_vld_tweak = true,
|
||||
.usxgmii_xfi_mode_sel = true,
|
||||
@@ -1442,6 +1449,7 @@ static const struct airoha_pcs_match_dat
|
||||
};
|
||||
|
||||
static const struct airoha_pcs_match_data an7583_pcs_usb = {
|
||||
+ .num_port = 1,
|
||||
.port_type = AIROHA_PCS_USB,
|
||||
.bringup = an7583_pcs_usb_phya_bringup,
|
||||
};
|
||||
@@ -132,7 +132,8 @@
|
||||
read-only;
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "u-boot,env";
|
||||
compatible = "u-boot,env-redundant-count";
|
||||
env-size = <0x1000>;
|
||||
|
||||
macaddr_uboot_ethaddr: ethaddr {
|
||||
};
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
* non-error returns are a promise to giveback() the urb later
|
||||
* we drop ownership so next owner (or urb unlink) can get it
|
||||
*/
|
||||
@@ -5591,6 +5694,7 @@ static const struct hc_driver xhci_hc_dr
|
||||
@@ -5600,6 +5703,7 @@ static const struct hc_driver xhci_hc_dr
|
||||
.endpoint_reset = xhci_endpoint_reset,
|
||||
.check_bandwidth = xhci_check_bandwidth,
|
||||
.reset_bandwidth = xhci_reset_bandwidth,
|
||||
|
||||
+1
-1
@@ -612,7 +612,7 @@ Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
||||
+...
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -24024,6 +24024,14 @@ T: git git://linuxtv.org/media.git
|
||||
@@ -24023,6 +24023,14 @@ T: git git://linuxtv.org/media.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
|
||||
F: drivers/media/i2c/imx415.c
|
||||
|
||||
|
||||
+1
-1
@@ -193,7 +193,7 @@ media: i2c: imx519: Squash fixes
|
||||
+...
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -24032,6 +24032,14 @@ T: git git://linuxtv.org/media_tree.git
|
||||
@@ -24031,6 +24031,14 @@ T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/imx477.yaml
|
||||
F: drivers/media/i2c/imx477.c
|
||||
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
|
||||
+...
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -24029,6 +24029,7 @@ M: Raspberry Pi Kernel Maintenance <kern
|
||||
@@ -24028,6 +24028,7 @@ M: Raspberry Pi Kernel Maintenance <kern
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
|
||||
+1
-1
@@ -137,7 +137,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
+...
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -24073,6 +24073,14 @@ T: git git://linuxtv.org/media_tree.git
|
||||
@@ -24072,6 +24072,14 @@ T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/imx519.yaml
|
||||
F: drivers/media/i2c/imx519.c
|
||||
|
||||
|
||||
+1
-1
@@ -271,7 +271,7 @@ Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
||||
+...
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -24078,7 +24078,7 @@ M: Raspberry Pi Kernel Maintenance <kern
|
||||
@@ -24077,7 +24077,7 @@ M: Raspberry Pi Kernel Maintenance <kern
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
|
||||
+...
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -22407,6 +22407,13 @@ L: linux-iio@vger.kernel.org
|
||||
@@ -22406,6 +22406,13 @@ L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/iio/light/rohm-bu27034.c
|
||||
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
|
||||
+
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -21522,6 +21522,11 @@ L: linux-edac@vger.kernel.org
|
||||
@@ -21521,6 +21521,11 @@ L: linux-edac@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/ras/amd/fmpm.c
|
||||
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -21526,6 +21526,7 @@ RASPBERRY PI RP2040 GPIO BRIDGE DRIVER
|
||||
@@ -21525,6 +21525,7 @@ RASPBERRY PI RP2040 GPIO BRIDGE DRIVER
|
||||
M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
|
||||
|
||||
@@ -150,7 +150,7 @@ Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
|
||||
+
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -24078,6 +24078,13 @@ F: Documentation/devicetree/bindings/med
|
||||
@@ -24077,6 +24077,13 @@ F: Documentation/devicetree/bindings/med
|
||||
F: Documentation/devicetree/bindings/media/i2c/imx477.yaml
|
||||
F: drivers/media/i2c/imx477.c
|
||||
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -24084,6 +24084,7 @@ L: linux-media@vger.kernel.org
|
||||
@@ -24083,6 +24083,7 @@ L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -21528,6 +21528,16 @@ S: Maintained
|
||||
@@ -21527,6 +21527,16 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
|
||||
F: drivers/spi/spi-rp2040-gpio-bridge.c
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
--- a/drivers/pci/quirks.c
|
||||
+++ b/drivers/pci/quirks.c
|
||||
@@ -6293,6 +6293,22 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
|
||||
@@ -6278,6 +6278,22 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x56b1, aspm_l1_acceptable_latency);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x56c0, aspm_l1_acceptable_latency);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x56c1, aspm_l1_acceptable_latency);
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
|
||||
{
|
||||
struct xhci_segment *seg;
|
||||
@@ -4991,7 +4995,7 @@ static u16 xhci_calculate_u1_timeout(str
|
||||
@@ -5000,7 +5004,7 @@ static u16 xhci_calculate_u1_timeout(str
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc);
|
||||
else
|
||||
timeout_ns = udev->u1_params.sel;
|
||||
@@ -5055,7 +5059,7 @@ static u16 xhci_calculate_u2_timeout(str
|
||||
@@ -5064,7 +5068,7 @@ static u16 xhci_calculate_u2_timeout(str
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ This reverts commit 6bd54195d0b29330576542c8128e7a5c58d6bcdd.
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -21528,16 +21528,6 @@ S: Maintained
|
||||
@@ -21527,16 +21527,6 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
|
||||
F: drivers/spi/spi-rp2040-gpio-bridge.c
|
||||
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -21528,6 +21528,16 @@ S: Maintained
|
||||
@@ -21527,6 +21527,16 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
|
||||
F: drivers/spi/spi-rp2040-gpio-bridge.c
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#define PCIE_AHB_TRANS_BASE0_L 0x438
|
||||
#define PCIE_AHB_TRANS_BASE0_H 0x43c
|
||||
#define AHB2PCIE_SIZE(x) ((x) & GENMASK(4, 0))
|
||||
@@ -746,6 +752,86 @@ static int mtk_pcie_startup_port_v2(stru
|
||||
@@ -750,6 +756,86 @@ static int mtk_pcie_startup_port_v2(stru
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
@@ -1107,6 +1193,20 @@ static int mtk_pcie_probe(struct platfor
|
||||
@@ -1120,6 +1206,20 @@ static int mtk_pcie_probe(struct platfor
|
||||
if (err)
|
||||
goto put_resources;
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
return 0;
|
||||
|
||||
put_resources:
|
||||
@@ -1216,12 +1316,19 @@ static const struct mtk_pcie_soc mtk_pci
|
||||
@@ -1233,12 +1333,19 @@ static const struct mtk_pcie_soc mtk_pci
|
||||
.setup_irq = mtk_pcie_setup_irq,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
From 6d5fbecd0213489bc4de71a0da194d18e654fd6e Mon Sep 17 00:00:00 2001
|
||||
From: Kyle Hendry <kylehendrydev@gmail.com>
|
||||
Date: Sun, 21 Jun 2026 11:47:02 -0700
|
||||
Subject: MIPS: mm: Add check for highmem before removing memory block
|
||||
|
||||
If a device has less physical memory than the highmem threshold
|
||||
bootmem_init() doesn't set highstart_pfn. This results in highmem_init()
|
||||
wrongly disabling the entire memory range if the cpu doesn't support
|
||||
highmem. Add a check that highstart_pfn is non zero before removing the
|
||||
highmem block.
|
||||
|
||||
Fixes: f171b55f1441 ("mips: fix HIGHMEM initialization")
|
||||
Signed-off-by: Kyle Hendry <kylehendrydev@gmail.com>
|
||||
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||
---
|
||||
arch/mips/mm/init.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/mips/mm/init.c
|
||||
+++ b/arch/mips/mm/init.c
|
||||
@@ -431,10 +431,11 @@ static inline void __init highmem_init(v
|
||||
unsigned long tmp;
|
||||
|
||||
/*
|
||||
- * If CPU cannot support HIGHMEM discard the memory above highstart_pfn
|
||||
+ * If CPU cannot support HIGHMEM discard any memory above highstart_pfn
|
||||
*/
|
||||
if (cpu_has_dc_aliases) {
|
||||
- memblock_remove(PFN_PHYS(highstart_pfn), -1);
|
||||
+ if (highstart_pfn)
|
||||
+ memblock_remove(PFN_PHYS(highstart_pfn), -1);
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -25056,6 +25056,7 @@ L: netdev@vger.kernel.org
|
||||
@@ -25055,6 +25055,7 @@ L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: include/net/pkt_cls.h
|
||||
F: include/net/pkt_sched.h
|
||||
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
From 53b3e60edb674b442b2b3bbdba484667b0f47a5d Mon Sep 17 00:00:00 2001
|
||||
From: Adrian Bente <adibente@gmail.com>
|
||||
Date: Thu, 28 May 2026 10:08:51 +0300
|
||||
Subject: [PATCH] netfilter: flowtable: fix offloaded ct timeout never being extended
|
||||
|
||||
OpenWrt has recently migrated many platforms to kernel 6.18. On the
|
||||
MediaTek platform, which supports hardware network offloading, WiFi
|
||||
connections accelerated via the WED path were observed to drop after
|
||||
roughly 300 seconds.
|
||||
|
||||
After several debugging sessions, assisted by the Claude LLM, the
|
||||
problem was narrowed down as follows:
|
||||
|
||||
nf_flow_table_extend_ct_timeout() extends ct->timeout for offloaded
|
||||
flows using:
|
||||
|
||||
cmpxchg(&ct->timeout, expires, new_timeout);
|
||||
|
||||
'expires' comes from nf_ct_expires(ct) and is a relative value, while
|
||||
ct->timeout holds an absolute timestamp. The two are never equal, so
|
||||
the cmpxchg always fails and the timeout is never extended.
|
||||
|
||||
This goes unnoticed for most flows, but a long-lived hardware (WED)
|
||||
offloaded flow on MediaTek MT7986 eventually has ct->timeout decay to
|
||||
zero, the conntrack entry is reaped and the connection breaks.
|
||||
|
||||
Open-code the relative value from a single READ_ONCE(ct->timeout)
|
||||
snapshot and compare against that same absolute snapshot in the
|
||||
cmpxchg, so the timeout extension actually takes effect while the
|
||||
datapath remains authoritative if it updates ct->timeout concurrently.
|
||||
|
||||
Fixes: 03428ca5cee9 ("netfilter: conntrack: rework offload nf_conn timeout extension logic")
|
||||
Cc: stable@vger.kernel.org
|
||||
Suggested-by: Florian Westphal <fw@strlen.de>
|
||||
Signed-off-by: Adrian Bente <adibente@gmail.com>
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
net/netfilter/nf_flow_table_core.c | 13 +++++++++----
|
||||
1 file changed, 9 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -500,8 +500,13 @@ static u32 nf_flow_table_tcp_timeout(con
|
||||
*/
|
||||
static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct)
|
||||
{
|
||||
- static const u32 min_timeout = 5 * 60 * HZ;
|
||||
- u32 expires = nf_ct_expires(ct);
|
||||
+ static const s32 min_timeout = 5 * 60 * HZ;
|
||||
+ u32 ct_timeout = READ_ONCE(ct->timeout);
|
||||
+ s32 expires;
|
||||
+
|
||||
+ expires = ct_timeout - nfct_time_stamp;
|
||||
+ if (expires <= 0) /* already expired */
|
||||
+ return;
|
||||
|
||||
/* normal case: large enough timeout, nothing to do. */
|
||||
if (likely(expires >= min_timeout))
|
||||
@@ -519,7 +524,7 @@ static void nf_flow_table_extend_ct_time
|
||||
if (nf_ct_is_confirmed(ct) &&
|
||||
test_bit(IPS_OFFLOAD_BIT, &ct->status)) {
|
||||
u8 l4proto = nf_ct_protonum(ct);
|
||||
- u32 new_timeout = true;
|
||||
+ u32 new_timeout = 1;
|
||||
|
||||
switch (l4proto) {
|
||||
case IPPROTO_UDP:
|
||||
@@ -544,7 +549,7 @@ static void nf_flow_table_extend_ct_time
|
||||
*/
|
||||
if (new_timeout) {
|
||||
new_timeout += nfct_time_stamp;
|
||||
- cmpxchg(&ct->timeout, expires, new_timeout);
|
||||
+ cmpxchg(&ct->timeout, ct_timeout, new_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ Signed-off-by: Yury Norov (NVIDIA) <yury.norov@gmail.com>
|
||||
|
||||
--- a/sound/usb/mixer_quirks.c
|
||||
+++ b/sound/usb/mixer_quirks.c
|
||||
@@ -3308,10 +3308,6 @@ static int snd_bbfpro_controls_create(st
|
||||
@@ -3325,10 +3325,6 @@ static int snd_bbfpro_controls_create(st
|
||||
#define RME_DIGIFACE_REGISTER(reg, mask) (((reg) << 16) | (mask))
|
||||
#define RME_DIGIFACE_INVERT BIT(31)
|
||||
|
||||
|
||||
@@ -1215,7 +1215,7 @@ CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
# CONFIG_CRYPTO_PCBC is not set
|
||||
CONFIG_CRYPTO_PCRYPT=y
|
||||
# CONFIG_CRYPTO_PCRYPT is not set
|
||||
# CONFIG_CRYPTO_POLY1305 is not set
|
||||
# CONFIG_CRYPTO_POLY1305_ARM is not set
|
||||
# CONFIG_CRYPTO_POLY1305_MIPS is not set
|
||||
@@ -6683,6 +6683,7 @@ CONFIG_TCP_CONG_CUBIC=y
|
||||
# CONFIG_TCS3414 is not set
|
||||
# CONFIG_TCS3472 is not set
|
||||
# CONFIG_TEE is not set
|
||||
# CONFIG_TEE_BNXT_FW is not set
|
||||
# CONFIG_TEGRA_AHB is not set
|
||||
# CONFIG_TEGRA_HOST1X is not set
|
||||
# CONFIG_TEHUTI is not set
|
||||
|
||||
@@ -1279,7 +1279,7 @@ CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
# CONFIG_CRYPTO_PCBC is not set
|
||||
CONFIG_CRYPTO_PCRYPT=y
|
||||
# CONFIG_CRYPTO_PCRYPT is not set
|
||||
# CONFIG_CRYPTO_POLY1305 is not set
|
||||
# CONFIG_CRYPTO_POLY1305_ARM is not set
|
||||
# CONFIG_CRYPTO_POLY1305_NEON is not set
|
||||
@@ -7052,6 +7052,7 @@ CONFIG_TCP_CONG_CUBIC=y
|
||||
# CONFIG_TCS3414 is not set
|
||||
# CONFIG_TCS3472 is not set
|
||||
# CONFIG_TEE is not set
|
||||
# CONFIG_TEE_BNXT_FW is not set
|
||||
# CONFIG_TEGRA_AHB is not set
|
||||
# CONFIG_TEGRA_HOST1X is not set
|
||||
# CONFIG_TEHUTI is not set
|
||||
|
||||
@@ -1070,9 +1070,9 @@ static int net_activate(struct led_classdev *led_cdev)
|
||||
*/
|
||||
parsed = parse_family_token(fn, &online);
|
||||
if (parsed < 0) {
|
||||
pr_info("network: unknown function '%s' for LED %s\n",
|
||||
pr_warn("network: cannot infer family from '%s' for LED %s, defaulting to 'wlan'\n",
|
||||
fn ?: "<NULL>", name);
|
||||
return -EINVAL;
|
||||
parsed = NET_TRIG_WLAN;
|
||||
}
|
||||
|
||||
if (online) {
|
||||
|
||||
@@ -1056,7 +1056,6 @@ static struct genl_family switch_fam = {
|
||||
.resv_start_op = SWITCH_CMD_SET_VLAN + 1,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static void
|
||||
of_switch_load_portmap(struct switch_dev *dev)
|
||||
{
|
||||
@@ -1085,19 +1084,37 @@ of_switch_load_portmap(struct switch_dev *dev)
|
||||
}
|
||||
|
||||
phys = be32_to_cpup(prop++);
|
||||
if ((phys < 0) | (phys >= dev->ports)) {
|
||||
if (phys >= dev->ports) {
|
||||
pr_err("%s: physical port index out of range\n",
|
||||
port->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL);
|
||||
if (!dev->portmap[phys].s)
|
||||
continue;
|
||||
dev->portmap[phys].virt = be32_to_cpup(prop);
|
||||
pr_debug("Found port: %s, physical: %d, virtual: %d\n",
|
||||
segment, phys, dev->portmap[phys].virt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
switch_free_portmap(struct switch_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (dev->portmap) {
|
||||
for (i = 0; i < dev->ports; i++)
|
||||
kfree(dev->portmap[i].s);
|
||||
|
||||
kfree(dev->portmap);
|
||||
dev->portmap = NULL;
|
||||
}
|
||||
|
||||
kfree(dev->portbuf);
|
||||
dev->portbuf = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
register_switch(struct switch_dev *dev, struct net_device *netdev)
|
||||
@@ -1149,25 +1166,31 @@ register_switch(struct switch_dev *dev, struct net_device *netdev)
|
||||
|
||||
if (i == max_switches) {
|
||||
swconfig_unlock();
|
||||
switch_free_portmap(dev);
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (dev->ports)
|
||||
if (IS_ENABLED(CONFIG_OF) && dev->ports)
|
||||
of_switch_load_portmap(dev);
|
||||
#endif
|
||||
|
||||
/* fill device name */
|
||||
snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i);
|
||||
|
||||
list_add_tail(&dev->dev_list, &swdevs);
|
||||
swconfig_unlock();
|
||||
|
||||
err = swconfig_create_led_trigger(dev);
|
||||
if (err)
|
||||
return err;
|
||||
goto unlink;
|
||||
|
||||
return 0;
|
||||
|
||||
unlink:
|
||||
swconfig_lock();
|
||||
list_del(&dev->dev_list);
|
||||
swconfig_unlock();
|
||||
switch_free_portmap(dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_switch);
|
||||
|
||||
@@ -1175,12 +1198,12 @@ void
|
||||
unregister_switch(struct switch_dev *dev)
|
||||
{
|
||||
swconfig_destroy_led_trigger(dev);
|
||||
kfree(dev->portbuf);
|
||||
mutex_lock(&dev->sw_mutex);
|
||||
swconfig_lock();
|
||||
list_del(&dev->dev_list);
|
||||
swconfig_unlock();
|
||||
mutex_unlock(&dev->sw_mutex);
|
||||
switch_free_portmap(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_switch);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Subject: [PATCH] Kconfig: add tristate for OID and ASNI string
|
||||
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -2191,7 +2191,7 @@ config PADATA
|
||||
@@ -2192,7 +2192,7 @@ config PADATA
|
||||
bool
|
||||
|
||||
config ASN1
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-6.18 = .38
|
||||
LINUX_KERNEL_HASH-6.18.38 = ac26e508abd56e9f8b89872b6e10c49fc823bcc70d8068a5d8504c1a7c4ff045
|
||||
LINUX_VERSION-6.18 = .39
|
||||
LINUX_KERNEL_HASH-6.18.39 = a7a7e3d2ae9d95e74197223a8d4eb5f6be7aac21b6e6de27e9685d001c1f8cb0
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -26274,6 +26274,12 @@ F: Documentation/filesystems/ubifs-authe
|
||||
@@ -26273,6 +26273,12 @@ F: Documentation/filesystems/ubifs-authe
|
||||
F: Documentation/filesystems/ubifs.rst
|
||||
F: fs/ubifs/
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -15790,7 +15790,9 @@ M: Daniel Golle <daniel@makrotopia.org>
|
||||
@@ -15789,7 +15789,9 @@ M: Daniel Golle <daniel@makrotopia.org>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/pcs/pcs-mtk-lynxi.c
|
||||
|
||||
@@ -25,7 +25,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
|
||||
--- a/drivers/pci/quirks.c
|
||||
+++ b/drivers/pci/quirks.c
|
||||
@@ -316,6 +316,7 @@ static void quirk_mmio_always_on(struct
|
||||
@@ -301,6 +301,7 @@ static void quirk_mmio_always_on(struct
|
||||
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
|
||||
|
||||
@@ -33,7 +33,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
/*
|
||||
* The Mellanox Tavor device gives false positive parity errors. Disable
|
||||
* parity error reporting.
|
||||
@@ -3519,6 +3520,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
|
||||
@@ -3504,6 +3505,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
|
||||
|
||||
@@ -42,7 +42,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
/*
|
||||
* Ivytown NTB BAR sizes are misreported by the hardware due to an erratum.
|
||||
* To work around this, query the size it should be configured to by the
|
||||
@@ -3544,6 +3547,8 @@ static void quirk_intel_ntb(struct pci_d
|
||||
@@ -3529,6 +3532,8 @@ static void quirk_intel_ntb(struct pci_d
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb);
|
||||
|
||||
@@ -51,7 +51,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
/*
|
||||
* Some BIOS implementations leave the Intel GPU interrupts enabled, even
|
||||
* though no one is handling them (e.g., if the i915 driver is never
|
||||
@@ -3582,6 +3587,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
|
||||
@@ -3567,6 +3572,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
|
||||
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
From 5099807f335ce4f783f0578bef7278fffad30b07 Mon Sep 17 00:00:00 2001
|
||||
From: Kory Maincent <kory.maincent@bootlin.com>
|
||||
Date: Wed, 15 Apr 2026 15:02:59 +0200
|
||||
Subject: [PATCH] net: pse-pd: fix out-of-bounds bitmap access in pse_isr() on
|
||||
32-bit
|
||||
|
||||
In pse_isr(), notifs_mask was declared as a single unsigned long on the
|
||||
stack (32 bits on 32-bit architectures). For PSE controllers with more
|
||||
than 32 ports, this causes two problems:
|
||||
|
||||
- map_event callbacks could wrote bit positions >= 32 via
|
||||
*notifs_mask |= BIT(i), which is undefined behaviour on a 32-bit
|
||||
unsigned long and corrupts adjacent stack memory.
|
||||
|
||||
- for_each_set_bit(i, ¬ifs_mask, pcdev->nr_lines) treats
|
||||
¬ifs_mask as a multi-word bitmap and reads beyond the single
|
||||
unsigned long when nr_lines > BITS_PER_LONG.
|
||||
|
||||
Fix this by moving notifs_mask out of the stack and into struct pse_irq
|
||||
as a dynamically allocated bitmap. It is sized with
|
||||
BITS_TO_LONGS(pcdev->nr_lines) words in devm_pse_irq_helper(), so it
|
||||
is always wide enough regardless of the host word size.
|
||||
|
||||
[Jakub]: No upstream driver currently supports >=32 ports.
|
||||
|
||||
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
|
||||
Link: https://patch.msgid.link/20260415130300.806152-1-kory.maincent@bootlin.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/pse-pd/pse_core.c | 13 +++++++++----
|
||||
1 file changed, 9 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/pse-pd/pse_core.c
|
||||
+++ b/drivers/net/pse-pd/pse_core.c
|
||||
@@ -1170,6 +1170,7 @@ struct pse_irq {
|
||||
struct pse_controller_dev *pcdev;
|
||||
struct pse_irq_desc desc;
|
||||
unsigned long *notifs;
|
||||
+ unsigned long *notifs_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1247,7 +1248,6 @@ static int pse_set_config_isr(struct pse
|
||||
static irqreturn_t pse_isr(int irq, void *data)
|
||||
{
|
||||
struct pse_controller_dev *pcdev;
|
||||
- unsigned long notifs_mask = 0;
|
||||
struct pse_irq_desc *desc;
|
||||
struct pse_irq *h = data;
|
||||
int ret, i;
|
||||
@@ -1257,14 +1257,15 @@ static irqreturn_t pse_isr(int irq, void
|
||||
|
||||
/* Clear notifs mask */
|
||||
memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs));
|
||||
+ bitmap_zero(h->notifs_mask, pcdev->nr_lines);
|
||||
mutex_lock(&pcdev->lock);
|
||||
- ret = desc->map_event(irq, pcdev, h->notifs, ¬ifs_mask);
|
||||
- if (ret || !notifs_mask) {
|
||||
+ ret = desc->map_event(irq, pcdev, h->notifs, h->notifs_mask);
|
||||
+ if (ret || bitmap_empty(h->notifs_mask, pcdev->nr_lines)) {
|
||||
mutex_unlock(&pcdev->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
- for_each_set_bit(i, ¬ifs_mask, pcdev->nr_lines) {
|
||||
+ for_each_set_bit(i, h->notifs_mask, pcdev->nr_lines) {
|
||||
unsigned long notifs, rnotifs;
|
||||
struct pse_ntf ntf = {};
|
||||
|
||||
@@ -1340,6 +1341,10 @@ int devm_pse_irq_helper(struct pse_contr
|
||||
if (!h->notifs)
|
||||
return -ENOMEM;
|
||||
|
||||
+ h->notifs_mask = devm_bitmap_zalloc(dev, pcdev->nr_lines, GFP_KERNEL);
|
||||
+ if (!h->notifs_mask)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL, pse_isr,
|
||||
IRQF_ONESHOT | irq_flags,
|
||||
irq_name, h);
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
From a2d81faf75c1661d7a5977725731f481ba8de92d Mon Sep 17 00:00:00 2001
|
||||
From: Carlo Szelinsky <github@szelinsky.de>
|
||||
Date: Sat, 23 May 2026 21:32:58 +0200
|
||||
Subject: [PATCH] net: pse-pd: disable IRQ before freeing PI data in unregister
|
||||
|
||||
pse_controller_unregister() frees the PI array via pse_release_pis()
|
||||
before disabling the controller IRQ. The threaded IRQ handler pse_isr()
|
||||
walks pcdev->pi[] (via pse_set_config_isr() and
|
||||
regulator_notifier_call_chain() on pcdev->pi[i].rdev), so an interrupt
|
||||
arriving in the window between pse_release_pis() and disable_irq()
|
||||
dereferences freed memory.
|
||||
|
||||
Disable the IRQ first, then release the PI array. cancel_work_sync()
|
||||
for the notification worker stays after pse_release_pis(): the worker
|
||||
only touches the kfifo and the pse_control list, not pcdev->pi.
|
||||
|
||||
Fixes: ffef61d6d273 ("net: pse-pd: Add support for budget evaluation strategies")
|
||||
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
|
||||
---
|
||||
drivers/net/pse-pd/pse_core.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/pse-pd/pse_core.c
|
||||
+++ b/drivers/net/pse-pd/pse_core.c
|
||||
@@ -1115,9 +1115,9 @@ EXPORT_SYMBOL_GPL(pse_controller_registe
|
||||
void pse_controller_unregister(struct pse_controller_dev *pcdev)
|
||||
{
|
||||
pse_flush_pw_ds(pcdev);
|
||||
- pse_release_pis(pcdev);
|
||||
if (pcdev->irq)
|
||||
disable_irq(pcdev->irq);
|
||||
+ pse_release_pis(pcdev);
|
||||
cancel_work_sync(&pcdev->ntf_work);
|
||||
kfifo_free(&pcdev->ntf_fifo);
|
||||
mutex_lock(&pse_list_mutex);
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
From c4bd3afcf943491228e284cc6e68a145fcd07c2b Mon Sep 17 00:00:00 2001
|
||||
From: Carlo Szelinsky <github@szelinsky.de>
|
||||
Date: Sat, 23 May 2026 21:33:24 +0200
|
||||
Subject: [PATCH] net: pse-pd: guard against freed PI data on regulator disable
|
||||
|
||||
PSE PI regulators are devm-registered inside pse_controller_register(),
|
||||
which runs before devres_add() arms the controller's own release in
|
||||
devm_pse_controller_register(). On driver detach, devres unwinds in LIFO
|
||||
order, so pse_controller_unregister() runs first and frees pcdev->pi via
|
||||
pse_release_pis(); the regulators are torn down afterwards.
|
||||
|
||||
When regulator_unregister() flushes a pending disable, the regulator core
|
||||
invokes pse_pi_disable(), which dereferences pcdev->pi[id] (directly and
|
||||
via _pse_pi_disable() -> pse_pi_deallocate_pw_budget()). At that point the
|
||||
PI array is already freed, so this is a use-after-free.
|
||||
|
||||
pse_release_pis() now clears pcdev->pi after freeing it, and
|
||||
pse_pi_disable() bails out under the lock when pcdev->pi is NULL, so a
|
||||
late disable from the regulator core is a no-op once the controller has
|
||||
been unregistered.
|
||||
|
||||
Fixes: ffef61d6d273 ("net: pse-pd: Add support for budget evaluation strategies")
|
||||
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
|
||||
---
|
||||
drivers/net/pse-pd/pse_core.c | 13 ++++++++++---
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/pse-pd/pse_core.c
|
||||
+++ b/drivers/net/pse-pd/pse_core.c
|
||||
@@ -145,6 +145,7 @@ static void pse_release_pis(struct pse_c
|
||||
of_node_put(pcdev->pi[i].np);
|
||||
}
|
||||
kfree(pcdev->pi);
|
||||
+ pcdev->pi = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -702,15 +703,21 @@ static int pse_pi_enable(struct regulato
|
||||
static int pse_pi_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
|
||||
- struct pse_pi *pi;
|
||||
int id, ret;
|
||||
|
||||
id = rdev_get_id(rdev);
|
||||
- pi = &pcdev->pi[id];
|
||||
mutex_lock(&pcdev->lock);
|
||||
+ /* The controller may already be unregistered (pcdev->pi freed) by the
|
||||
+ * time the regulator core flushes a deferred disable during
|
||||
+ * regulator_unregister(). Bail out to avoid touching freed PI data.
|
||||
+ */
|
||||
+ if (!pcdev->pi) {
|
||||
+ mutex_unlock(&pcdev->lock);
|
||||
+ return 0;
|
||||
+ }
|
||||
ret = _pse_pi_disable(pcdev, id);
|
||||
if (!ret)
|
||||
- pi->admin_state_enabled = 0;
|
||||
+ pcdev->pi[id].admin_state_enabled = 0;
|
||||
|
||||
mutex_unlock(&pcdev->lock);
|
||||
return 0;
|
||||
+3
-3
@@ -20,7 +20,7 @@ Tested-by: Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
|
||||
--- a/drivers/net/pse-pd/pse_core.c
|
||||
+++ b/drivers/net/pse-pd/pse_core.c
|
||||
@@ -1138,6 +1138,9 @@ int pse_controller_register(struct pse_c
|
||||
@@ -1145,6 +1145,9 @@ int pse_controller_register(struct pse_c
|
||||
list_add(&pcdev->list, &pse_controller_list);
|
||||
mutex_unlock(&pse_list_mutex);
|
||||
|
||||
@@ -30,7 +30,7 @@ Tested-by: Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pse_controller_register);
|
||||
@@ -1148,6 +1151,9 @@ EXPORT_SYMBOL_GPL(pse_controller_registe
|
||||
@@ -1155,6 +1158,9 @@ EXPORT_SYMBOL_GPL(pse_controller_registe
|
||||
*/
|
||||
void pse_controller_unregister(struct pse_controller_dev *pcdev)
|
||||
{
|
||||
@@ -38,5 +38,5 @@ Tested-by: Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
+ PSE_UNREGISTERED, pcdev);
|
||||
+
|
||||
pse_flush_pw_ds(pcdev);
|
||||
pse_release_pis(pcdev);
|
||||
if (pcdev->irq)
|
||||
disable_irq(pcdev->irq);
|
||||
|
||||
+1
-1
@@ -380,7 +380,7 @@ Tested-by: Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
dev_err(sfp->dev, "phy_device_register failed: %pe\n",
|
||||
--- a/drivers/net/pse-pd/pse_core.c
|
||||
+++ b/drivers/net/pse-pd/pse_core.c
|
||||
@@ -2016,3 +2016,17 @@ bool pse_has_c33(struct pse_control *pse
|
||||
@@ -2028,3 +2028,17 @@ bool pse_has_c33(struct pse_control *pse
|
||||
return psec->pcdev->types & ETHTOOL_PSE_C33;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pse_has_c33);
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
From af1b9d9d0b357d14e54abff6ec9335e5fb426f75 Mon Sep 17 00:00:00 2001
|
||||
From: Carlo Szelinsky <github@szelinsky.de>
|
||||
Date: Sun, 29 Mar 2026 16:24:08 +0200
|
||||
Subject: dt-bindings: net: pse-pd: add poll-interval-ms property
|
||||
|
||||
Add the optional poll-interval-ms property for PSE controllers that
|
||||
use poll-based event detection instead of interrupts. Defaults to
|
||||
500ms if not specified.
|
||||
|
||||
Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
|
||||
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
|
||||
|
||||
---
|
||||
--- a/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml
|
||||
+++ b/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml
|
||||
@@ -27,6 +27,14 @@ properties:
|
||||
subnode. This property is deprecated, please use pse-pis instead.
|
||||
enum: [0, 1]
|
||||
|
||||
+ poll-interval-ms:
|
||||
+ description:
|
||||
+ Polling interval in milliseconds for PSE controllers using
|
||||
+ poll-based event detection instead of interrupts. Used when the
|
||||
+ controller lacks IRQ support or the IRQ line is not wired.
|
||||
+ default: 500
|
||||
+ minimum: 50
|
||||
+
|
||||
pse-pis:
|
||||
type: object
|
||||
description:
|
||||
@@ -0,0 +1,330 @@
|
||||
From 34551486030a0b5b3a1bac4bb293633f0e5e3e0e Mon Sep 17 00:00:00 2001
|
||||
From: Carlo Szelinsky <github@szelinsky.de>
|
||||
Date: Sun, 29 Mar 2026 16:26:08 +0200
|
||||
Subject: net: pse-pd: add devm_pse_poll_helper()
|
||||
|
||||
Extract the common event handling loop from pse_isr() into a shared
|
||||
pse_handle_events() function, and add a generic poll-based alternative
|
||||
to the IRQ path for PSE controllers that lack interrupt support or
|
||||
have IRQ lines not wired on the board.
|
||||
|
||||
The new devm_pse_poll_helper() function sets up a delayed work that
|
||||
periodically calls the driver's map_event callback to detect state
|
||||
changes, feeding events into the existing ntf_fifo / pse_send_ntf_worker
|
||||
notification pipeline. This reuses the same pse_irq_desc interface as
|
||||
the IRQ path: the driver provides a map_event callback that populates
|
||||
per-PI notification arrays.
|
||||
|
||||
The poll worker uses system_freezable_wq to avoid running during system
|
||||
suspend when the underlying hardware (e.g. I2C bus) may be inaccessible.
|
||||
|
||||
devm_pse_poll_helper() only allocates the per-PI state and initializes
|
||||
the delayed work; the work is armed by pse_controller_register() as the
|
||||
very last step on success, gated on pcdev->polling. Drivers set up the
|
||||
helper before registering the controller, so arming earlier would let
|
||||
pse_poll_worker() acquire pcdev->lock and push events into the ntf_fifo
|
||||
before they are initialized; and if probe failed after the helper but
|
||||
before registration, the work would fire against freed devres memory.
|
||||
Arming after a successful register closes both. Probe is a preemptible
|
||||
process and can be outscheduled at any point, so this is reachable in
|
||||
practice, not just in theory (e.g. a single-core SoC with the pse-pd
|
||||
core built as a module and a squashfs rootfs makes the boot heavy
|
||||
enough to lose the race).
|
||||
|
||||
The poll work is cancelled in pse_controller_unregister() before
|
||||
pse_release_pis() frees pcdev->pi, next to the IRQ disable, so neither
|
||||
the poll worker nor the IRQ handler can dereference the freed PI array.
|
||||
|
||||
The notifs_mask is allocated as a real bitmap via devm_bitmap_zalloc()
|
||||
and passed to pse_handle_events() and the driver's map_event callback
|
||||
as a pointer (mirroring the pattern from commit 5099807f335c
|
||||
("net: pse-pd: fix out-of-bounds bitmap access in pse_isr() on 32-bit"))
|
||||
so for_each_set_bit() does not read past a single unsigned long when
|
||||
nr_lines > BITS_PER_LONG.
|
||||
|
||||
The poll interval defaults to 500ms, balancing responsiveness against
|
||||
bus load (e.g. I2C).
|
||||
|
||||
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
|
||||
|
||||
---
|
||||
--- a/drivers/net/pse-pd/pse_core.c
|
||||
+++ b/drivers/net/pse-pd/pse_core.c
|
||||
@@ -15,10 +15,17 @@
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
+#include <linux/workqueue.h>
|
||||
#include <net/net_trackers.h>
|
||||
|
||||
#define PSE_PW_D_LIMIT INT_MAX
|
||||
|
||||
+/* Default poll interval for controllers without IRQ support.
|
||||
+ * 500ms provides a reasonable trade-off between responsiveness
|
||||
+ * (event detection, PD detection) and I2C bus utilization.
|
||||
+ */
|
||||
+#define PSE_DEFAULT_POLL_INTERVAL_MS 500
|
||||
+
|
||||
static DEFINE_MUTEX(pse_list_mutex);
|
||||
static LIST_HEAD(pse_controller_list);
|
||||
static DEFINE_XARRAY_ALLOC(pse_pw_d_map);
|
||||
@@ -1148,6 +1155,15 @@ int pse_controller_register(struct pse_c
|
||||
blocking_notifier_call_chain(&pse_controller_notifier,
|
||||
PSE_REGISTERED, pcdev);
|
||||
|
||||
+ /* Arm the poll work last, once everything is initialized and
|
||||
+ * registration has succeeded. devm_pse_poll_helper() only sets up the
|
||||
+ * delayed work; queuing it here ensures pse_poll_worker() never runs
|
||||
+ * against a half-initialized controller or one whose probe later fails.
|
||||
+ */
|
||||
+ if (pcdev->polling)
|
||||
+ queue_delayed_work(system_freezable_wq, &pcdev->poll_work,
|
||||
+ msecs_to_jiffies(pcdev->poll_interval_ms));
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pse_controller_register);
|
||||
@@ -1164,6 +1180,8 @@ void pse_controller_unregister(struct ps
|
||||
pse_flush_pw_ds(pcdev);
|
||||
if (pcdev->irq)
|
||||
disable_irq(pcdev->irq);
|
||||
+ if (pcdev->polling)
|
||||
+ cancel_delayed_work_sync(&pcdev->poll_work);
|
||||
pse_release_pis(pcdev);
|
||||
cancel_work_sync(&pcdev->ntf_work);
|
||||
kfifo_free(&pcdev->ntf_fifo);
|
||||
@@ -1286,66 +1304,104 @@ static int pse_set_config_isr(struct pse
|
||||
}
|
||||
|
||||
/**
|
||||
- * pse_isr - IRQ handler for PSE
|
||||
- * @irq: irq number
|
||||
- * @data: pointer to user interrupt structure
|
||||
+ * pse_handle_events - Process PSE events for all PIs
|
||||
+ * @pcdev: a pointer to the PSE controller device
|
||||
+ * @notifs: per-PI notification array
|
||||
+ * @notifs_mask: bitmap of PIs with events (sized for pcdev->nr_lines)
|
||||
*
|
||||
- * Return: irqreturn_t - status of IRQ
|
||||
+ * Common event handling shared between IRQ and poll paths.
|
||||
+ * Caller must hold pcdev->lock.
|
||||
*/
|
||||
-static irqreturn_t pse_isr(int irq, void *data)
|
||||
+static void pse_handle_events(struct pse_controller_dev *pcdev,
|
||||
+ unsigned long *notifs,
|
||||
+ unsigned long *notifs_mask)
|
||||
{
|
||||
- struct pse_controller_dev *pcdev;
|
||||
- struct pse_irq_desc *desc;
|
||||
- struct pse_irq *h = data;
|
||||
- int ret, i;
|
||||
-
|
||||
- desc = &h->desc;
|
||||
- pcdev = h->pcdev;
|
||||
-
|
||||
- /* Clear notifs mask */
|
||||
- memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs));
|
||||
- bitmap_zero(h->notifs_mask, pcdev->nr_lines);
|
||||
- mutex_lock(&pcdev->lock);
|
||||
- ret = desc->map_event(irq, pcdev, h->notifs, h->notifs_mask);
|
||||
- if (ret || bitmap_empty(h->notifs_mask, pcdev->nr_lines)) {
|
||||
- mutex_unlock(&pcdev->lock);
|
||||
- return IRQ_NONE;
|
||||
- }
|
||||
+ int i;
|
||||
|
||||
- for_each_set_bit(i, h->notifs_mask, pcdev->nr_lines) {
|
||||
- unsigned long notifs, rnotifs;
|
||||
+ for_each_set_bit(i, notifs_mask, pcdev->nr_lines) {
|
||||
+ unsigned long pi_notifs, rnotifs;
|
||||
struct pse_ntf ntf = {};
|
||||
+ int ret;
|
||||
|
||||
/* Do nothing PI not described */
|
||||
if (!pcdev->pi[i].rdev)
|
||||
continue;
|
||||
|
||||
- notifs = h->notifs[i];
|
||||
+ pi_notifs = notifs[i];
|
||||
if (pse_pw_d_is_sw_pw_control(pcdev, pcdev->pi[i].pw_d)) {
|
||||
- ret = pse_set_config_isr(pcdev, i, notifs);
|
||||
+ ret = pse_set_config_isr(pcdev, i, pi_notifs);
|
||||
if (ret)
|
||||
- notifs |= ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR;
|
||||
+ pi_notifs |= ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR;
|
||||
}
|
||||
|
||||
- dev_dbg(h->pcdev->dev,
|
||||
- "Sending PSE notification EVT 0x%lx\n", notifs);
|
||||
+ dev_dbg(pcdev->dev,
|
||||
+ "Sending PSE notification EVT 0x%lx\n", pi_notifs);
|
||||
|
||||
- ntf.notifs = notifs;
|
||||
+ ntf.notifs = pi_notifs;
|
||||
ntf.id = i;
|
||||
kfifo_in_spinlocked(&pcdev->ntf_fifo, &ntf, 1,
|
||||
&pcdev->ntf_fifo_lock);
|
||||
schedule_work(&pcdev->ntf_work);
|
||||
|
||||
- rnotifs = pse_to_regulator_notifs(notifs);
|
||||
+ rnotifs = pse_to_regulator_notifs(pi_notifs);
|
||||
regulator_notifier_call_chain(pcdev->pi[i].rdev, rnotifs,
|
||||
NULL);
|
||||
}
|
||||
+}
|
||||
|
||||
+/**
|
||||
+ * pse_isr - IRQ handler for PSE
|
||||
+ * @irq: irq number
|
||||
+ * @data: pointer to user interrupt structure
|
||||
+ *
|
||||
+ * Return: irqreturn_t - status of IRQ
|
||||
+ */
|
||||
+static irqreturn_t pse_isr(int irq, void *data)
|
||||
+{
|
||||
+ struct pse_controller_dev *pcdev;
|
||||
+ struct pse_irq *h = data;
|
||||
+ int ret;
|
||||
+
|
||||
+ pcdev = h->pcdev;
|
||||
+
|
||||
+ /* Clear notifs mask */
|
||||
+ memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs));
|
||||
+ bitmap_zero(h->notifs_mask, pcdev->nr_lines);
|
||||
+ mutex_lock(&pcdev->lock);
|
||||
+ ret = h->desc.map_event(irq, pcdev, h->notifs, h->notifs_mask);
|
||||
+ if (ret || bitmap_empty(h->notifs_mask, pcdev->nr_lines)) {
|
||||
+ mutex_unlock(&pcdev->lock);
|
||||
+ return IRQ_NONE;
|
||||
+ }
|
||||
+
|
||||
+ pse_handle_events(pcdev, h->notifs, h->notifs_mask);
|
||||
mutex_unlock(&pcdev->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
+static void pse_poll_worker(struct work_struct *work)
|
||||
+{
|
||||
+ struct pse_controller_dev *pcdev =
|
||||
+ container_of(work, struct pse_controller_dev,
|
||||
+ poll_work.work);
|
||||
+ int ret;
|
||||
+
|
||||
+ memset(pcdev->poll_notifs, 0,
|
||||
+ pcdev->nr_lines * sizeof(*pcdev->poll_notifs));
|
||||
+ bitmap_zero(pcdev->poll_notifs_mask, pcdev->nr_lines);
|
||||
+ mutex_lock(&pcdev->lock);
|
||||
+ ret = pcdev->poll_desc.map_event(0, pcdev, pcdev->poll_notifs,
|
||||
+ pcdev->poll_notifs_mask);
|
||||
+ if (!ret && !bitmap_empty(pcdev->poll_notifs_mask, pcdev->nr_lines))
|
||||
+ pse_handle_events(pcdev, pcdev->poll_notifs,
|
||||
+ pcdev->poll_notifs_mask);
|
||||
+ mutex_unlock(&pcdev->lock);
|
||||
+
|
||||
+ queue_delayed_work(system_freezable_wq, &pcdev->poll_work,
|
||||
+ msecs_to_jiffies(pcdev->poll_interval_ms));
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* devm_pse_irq_helper - Register IRQ based PSE event notifier
|
||||
* @pcdev: a pointer to the PSE
|
||||
@@ -1403,6 +1459,61 @@ int devm_pse_irq_helper(struct pse_contr
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pse_irq_helper);
|
||||
|
||||
+/**
|
||||
+ * devm_pse_poll_helper - Register poll-based PSE event notifier
|
||||
+ * @pcdev: a pointer to the PSE controller device
|
||||
+ * @d: PSE event description (uses same pse_irq_desc as IRQ path)
|
||||
+ *
|
||||
+ * For PSE controllers without IRQ support or with IRQ not wired. Sets
|
||||
+ * up a delayed work that periodically calls the driver's map_event
|
||||
+ * callback to detect state changes, feeding events into the standard
|
||||
+ * notification pipeline.
|
||||
+ *
|
||||
+ * The poll worker uses system_freezable_wq to ensure it does not run
|
||||
+ * during system suspend while the hardware may be inaccessible.
|
||||
+ *
|
||||
+ * Must be called before devm_pse_controller_register(): this helper only
|
||||
+ * sets up the delayed work, which pse_controller_register() arms as its
|
||||
+ * last step on success. Calling it afterwards leaves the work unarmed and
|
||||
+ * polling never starts.
|
||||
+ *
|
||||
+ * Return: 0 on success and errno on failure
|
||||
+ */
|
||||
+int devm_pse_poll_helper(struct pse_controller_dev *pcdev,
|
||||
+ const struct pse_irq_desc *d)
|
||||
+{
|
||||
+ struct device *dev = pcdev->dev;
|
||||
+
|
||||
+ if (!d || !d->map_event || !d->name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ pcdev->poll_desc = *d;
|
||||
+ pcdev->poll_notifs = devm_kcalloc(dev, pcdev->nr_lines,
|
||||
+ sizeof(*pcdev->poll_notifs),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!pcdev->poll_notifs)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pcdev->poll_notifs_mask = devm_bitmap_zalloc(dev, pcdev->nr_lines,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!pcdev->poll_notifs_mask)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ if (!pcdev->poll_interval_ms)
|
||||
+ pcdev->poll_interval_ms = PSE_DEFAULT_POLL_INTERVAL_MS;
|
||||
+
|
||||
+ INIT_DELAYED_WORK(&pcdev->poll_work, pse_poll_worker);
|
||||
+ pcdev->polling = true;
|
||||
+
|
||||
+ /* The poll work is armed by pse_controller_register() as the last
|
||||
+ * step on success, so it never runs against a half-initialized or
|
||||
+ * never-registered controller.
|
||||
+ */
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(devm_pse_poll_helper);
|
||||
+
|
||||
/* PSE control section */
|
||||
|
||||
static void __pse_control_release(struct kref *kref)
|
||||
--- a/include/linux/pse-pd/pse.h
|
||||
+++ b/include/linux/pse-pd/pse.h
|
||||
@@ -293,6 +293,12 @@ struct pse_ntf {
|
||||
* @pi: table of PSE PIs described in this controller device
|
||||
* @no_of_pse_pi: flag set if the pse_pis devicetree node is not used
|
||||
* @irq: PSE interrupt
|
||||
+ * @polling: flag indicating poll-based event detection is active
|
||||
+ * @poll_interval_ms: poll interval in milliseconds
|
||||
+ * @poll_work: delayed work for poll-based event detection
|
||||
+ * @poll_desc: copy of the driver's event descriptor for polling
|
||||
+ * @poll_notifs: per-PI notification scratch space for poll worker
|
||||
+ * @poll_notifs_mask: bitmap of PIs with events for poll worker
|
||||
* @pis_prio_max: Maximum value allowed for the PSE PIs priority
|
||||
* @supp_budget_eval_strategies: budget evaluation strategies supported
|
||||
* by the PSE
|
||||
@@ -313,6 +319,12 @@ struct pse_controller_dev {
|
||||
struct pse_pi *pi;
|
||||
bool no_of_pse_pi;
|
||||
int irq;
|
||||
+ bool polling;
|
||||
+ unsigned int poll_interval_ms;
|
||||
+ struct delayed_work poll_work;
|
||||
+ struct pse_irq_desc poll_desc;
|
||||
+ unsigned long *poll_notifs;
|
||||
+ unsigned long *poll_notifs_mask;
|
||||
unsigned int pis_prio_max;
|
||||
u32 supp_budget_eval_strategies;
|
||||
struct work_struct ntf_work;
|
||||
@@ -364,6 +376,8 @@ int devm_pse_controller_register(struct
|
||||
struct pse_controller_dev *pcdev);
|
||||
int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq,
|
||||
int irq_flags, const struct pse_irq_desc *d);
|
||||
+int devm_pse_poll_helper(struct pse_controller_dev *pcdev,
|
||||
+ const struct pse_irq_desc *d);
|
||||
|
||||
struct pse_control *of_pse_control_get(struct device_node *node,
|
||||
struct phy_device *phydev);
|
||||
@@ -0,0 +1,364 @@
|
||||
From 547266c0e2d887b338dee1d6e6693e987b2868cd Mon Sep 17 00:00:00 2001
|
||||
From: Carlo Szelinsky <github@szelinsky.de>
|
||||
Date: Sun, 29 Mar 2026 16:26:49 +0200
|
||||
Subject: net: pse-pd: add LED trigger support via notification path
|
||||
|
||||
Add per-PI "delivering" and "enabled" LED triggers to the PSE core
|
||||
subsystem. LED state is updated from the shared pse_handle_events()
|
||||
function whenever the IRQ or poll path detects a state change, as well
|
||||
as from the regulator enable/disable paths so that host-initiated
|
||||
admin state changes via ethtool are immediately reflected.
|
||||
|
||||
Each trigger registers an .activate callback that syncs a freshly-bound
|
||||
LED to the cached state, so an LED bound after pse_controller_register()
|
||||
(e.g. via sysfs) does not stay dark until the next hardware event.
|
||||
|
||||
The triggers are registered before the PI regulators are exposed in
|
||||
pse_controller_register(). of_load_pse_pis() has already populated
|
||||
pi[]/pi[i].np by then, which is all the trigger loop needs, and
|
||||
registering first closes the window where a consumer calling
|
||||
regulator_enable() as soon as the regulators appear could fire
|
||||
led_trigger_event() on a trigger whose led_cdevs list head is not yet
|
||||
initialized. A registration failure is fatal to the probe, matching the
|
||||
other allocations in the function.
|
||||
|
||||
The post-registration initial-state pass is run under pcdev->lock,
|
||||
matching pse_led_update()'s documented locking contract and avoiding
|
||||
races with concurrent regulator_enable() paths that share last_delivering
|
||||
/ last_enabled and the hardware ops. pse_handle_events() gains a
|
||||
lockdep_assert_held() to make that contract explicit and catch any
|
||||
future caller that forgets the lock.
|
||||
|
||||
pse_controller_unregister() clears pcdev->pi_led_trigs before returning,
|
||||
so a deferred regulator disable flushed during the regulator core's
|
||||
later teardown finds pse_led_update() short-circuited rather than
|
||||
walking soon-to-be-freed trigger state.
|
||||
|
||||
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
|
||||
|
||||
---
|
||||
--- a/drivers/net/pse-pd/pse_core.c
|
||||
+++ b/drivers/net/pse-pd/pse_core.c
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
+#include <linux/leds.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy.h>
|
||||
@@ -704,6 +705,168 @@ static int _pse_pi_delivery_power_sw_pw_
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#if IS_ENABLED(CONFIG_LEDS_TRIGGERS)
|
||||
+/**
|
||||
+ * pse_pi_get_states - Fetch current delivering/enabled state for a PI
|
||||
+ * @pcdev: PSE controller device
|
||||
+ * @id: PI index
|
||||
+ * @delivering: out, set to true if PI is currently delivering power
|
||||
+ * @enabled: out, set to true if PI is administratively enabled
|
||||
+ *
|
||||
+ * Queries hardware via the controller ops. Caller must hold pcdev->lock.
|
||||
+ *
|
||||
+ * Return: 0 on success, negative errno on failure.
|
||||
+ */
|
||||
+static int pse_pi_get_states(struct pse_controller_dev *pcdev, int id,
|
||||
+ bool *delivering, bool *enabled)
|
||||
+{
|
||||
+ struct pse_pw_status pw_status = {};
|
||||
+ struct pse_admin_state admin_state = {};
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = pcdev->ops->pi_get_pw_status(pcdev, id, &pw_status);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = pcdev->ops->pi_get_admin_state(pcdev, id, &admin_state);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ *delivering = pw_status.c33_pw_status ==
|
||||
+ ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING ||
|
||||
+ pw_status.podl_pw_status ==
|
||||
+ ETHTOOL_PODL_PSE_PW_D_STATUS_DELIVERING;
|
||||
+ *enabled = admin_state.c33_admin_state ==
|
||||
+ ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED ||
|
||||
+ admin_state.podl_admin_state ==
|
||||
+ ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pse_led_update - Update LED triggers for a PI based on current state
|
||||
+ * @pcdev: PSE controller device
|
||||
+ * @id: PI index
|
||||
+ *
|
||||
+ * Queries the current power status and admin state of the PI and
|
||||
+ * fires LED trigger events on state changes. Called from the
|
||||
+ * notification path and the regulator enable/disable paths.
|
||||
+ *
|
||||
+ * Must be called with pcdev->lock held.
|
||||
+ */
|
||||
+static void pse_led_update(struct pse_controller_dev *pcdev, int id)
|
||||
+{
|
||||
+ struct pse_pi_led_triggers *trigs;
|
||||
+ bool delivering, enabled;
|
||||
+
|
||||
+ if (!pcdev->pi_led_trigs)
|
||||
+ return;
|
||||
+
|
||||
+ trigs = &pcdev->pi_led_trigs[id];
|
||||
+ if (!trigs->delivering.name)
|
||||
+ return;
|
||||
+
|
||||
+ if (pse_pi_get_states(pcdev, id, &delivering, &enabled))
|
||||
+ return;
|
||||
+
|
||||
+ if (trigs->last_delivering != delivering) {
|
||||
+ trigs->last_delivering = delivering;
|
||||
+ led_trigger_event(&trigs->delivering,
|
||||
+ delivering ? LED_FULL : LED_OFF);
|
||||
+ }
|
||||
+
|
||||
+ if (trigs->last_enabled != enabled) {
|
||||
+ trigs->last_enabled = enabled;
|
||||
+ led_trigger_event(&trigs->enabled,
|
||||
+ enabled ? LED_FULL : LED_OFF);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Sync a freshly-bound LED to the cached trigger state. Without these
|
||||
+ * .activate callbacks, an LED bound to the trigger after
|
||||
+ * pse_controller_register() (e.g. via sysfs) would stay dark until the
|
||||
+ * next hardware event toggles state.
|
||||
+ */
|
||||
+static int pse_led_delivering_activate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct pse_pi_led_triggers *trigs =
|
||||
+ container_of(led_cdev->trigger, struct pse_pi_led_triggers,
|
||||
+ delivering);
|
||||
+
|
||||
+ led_set_brightness(led_cdev,
|
||||
+ trigs->last_delivering ? LED_FULL : LED_OFF);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int pse_led_enabled_activate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct pse_pi_led_triggers *trigs =
|
||||
+ container_of(led_cdev->trigger, struct pse_pi_led_triggers,
|
||||
+ enabled);
|
||||
+
|
||||
+ led_set_brightness(led_cdev,
|
||||
+ trigs->last_enabled ? LED_FULL : LED_OFF);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int pse_led_triggers_register(struct pse_controller_dev *pcdev)
|
||||
+{
|
||||
+ struct device *dev = pcdev->dev;
|
||||
+ const char *dev_id;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ dev_id = dev_name(dev);
|
||||
+
|
||||
+ pcdev->pi_led_trigs = devm_kcalloc(dev, pcdev->nr_lines,
|
||||
+ sizeof(*pcdev->pi_led_trigs),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!pcdev->pi_led_trigs)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ for (i = 0; i < pcdev->nr_lines; i++) {
|
||||
+ struct pse_pi_led_triggers *trigs = &pcdev->pi_led_trigs[i];
|
||||
+
|
||||
+ /* Skip PIs not described in device tree */
|
||||
+ if (!pcdev->no_of_pse_pi && !pcdev->pi[i].np)
|
||||
+ continue;
|
||||
+
|
||||
+ trigs->delivering.name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
+ "pse-%s:port%d:delivering",
|
||||
+ dev_id, i);
|
||||
+ if (!trigs->delivering.name)
|
||||
+ return -ENOMEM;
|
||||
+ trigs->delivering.activate = pse_led_delivering_activate;
|
||||
+
|
||||
+ ret = devm_led_trigger_register(dev, &trigs->delivering);
|
||||
+ if (ret) {
|
||||
+ trigs->delivering.name = NULL;
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ trigs->enabled.name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
+ "pse-%s:port%d:enabled",
|
||||
+ dev_id, i);
|
||||
+ if (!trigs->enabled.name)
|
||||
+ return -ENOMEM;
|
||||
+ trigs->enabled.activate = pse_led_enabled_activate;
|
||||
+
|
||||
+ ret = devm_led_trigger_register(dev, &trigs->enabled);
|
||||
+ if (ret) {
|
||||
+ trigs->enabled.name = NULL;
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+static inline void pse_led_update(struct pse_controller_dev *pcdev, int id) {}
|
||||
+static int pse_led_triggers_register(struct pse_controller_dev *pcdev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* CONFIG_LEDS_TRIGGERS */
|
||||
+
|
||||
static int pse_pi_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
|
||||
@@ -729,6 +892,7 @@ static int pse_pi_enable(struct regulato
|
||||
pcdev->pi[id].admin_state_enabled = 1;
|
||||
ret = 0;
|
||||
}
|
||||
+ pse_led_update(pcdev, id);
|
||||
mutex_unlock(&pcdev->lock);
|
||||
return ret;
|
||||
}
|
||||
@@ -736,6 +900,7 @@ static int pse_pi_enable(struct regulato
|
||||
ret = ops->pi_enable(pcdev, id);
|
||||
if (!ret)
|
||||
pcdev->pi[id].admin_state_enabled = 1;
|
||||
+ pse_led_update(pcdev, id);
|
||||
mutex_unlock(&pcdev->lock);
|
||||
|
||||
return ret;
|
||||
@@ -759,6 +924,7 @@ static int pse_pi_disable(struct regulat
|
||||
ret = _pse_pi_disable(pcdev, id);
|
||||
if (!ret)
|
||||
pcdev->pi[id].admin_state_enabled = 0;
|
||||
+ pse_led_update(pcdev, id);
|
||||
|
||||
mutex_unlock(&pcdev->lock);
|
||||
return 0;
|
||||
@@ -1119,6 +1285,17 @@ int pse_controller_register(struct pse_c
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ /* Register the LED triggers before exposing the regulators. The
|
||||
+ * trigger loop only needs pi[]/pi[i].np, which of_load_pse_pis()
|
||||
+ * has already populated. Registering first means a consumer that
|
||||
+ * calls regulator_enable() as soon as the regulators appear cannot
|
||||
+ * race against a half-initialized led_trigger (whose led_cdevs list
|
||||
+ * head is not yet set up).
|
||||
+ */
|
||||
+ ret = pse_led_triggers_register(pcdev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
/* Each regulator name len is pcdev dev name + 7 char +
|
||||
* int max digit number (10) + 1
|
||||
*/
|
||||
@@ -1148,6 +1325,19 @@ int pse_controller_register(struct pse_c
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ /* Query initial LED state for all PIs so already-active ports
|
||||
+ * are reflected immediately without waiting for a hardware event.
|
||||
+ * Hold pcdev->lock: regulators are already exposed and a
|
||||
+ * concurrent regulator_enable() would race on the hw callbacks
|
||||
+ * and on last_delivering / last_enabled.
|
||||
+ */
|
||||
+ mutex_lock(&pcdev->lock);
|
||||
+ for (i = 0; i < pcdev->nr_lines; i++) {
|
||||
+ if (pcdev->no_of_pse_pi || pcdev->pi[i].np)
|
||||
+ pse_led_update(pcdev, i);
|
||||
+ }
|
||||
+ mutex_unlock(&pcdev->lock);
|
||||
+
|
||||
mutex_lock(&pse_list_mutex);
|
||||
list_add(&pcdev->list, &pse_controller_list);
|
||||
mutex_unlock(&pse_list_mutex);
|
||||
@@ -1183,6 +1373,12 @@ void pse_controller_unregister(struct ps
|
||||
if (pcdev->polling)
|
||||
cancel_delayed_work_sync(&pcdev->poll_work);
|
||||
pse_release_pis(pcdev);
|
||||
+ /* The pi_led_trigs array is devm-allocated and freed only after this
|
||||
+ * function returns. Clear the pointer now so a deferred regulator
|
||||
+ * disable flushed during regulator_unregister() makes pse_led_update()
|
||||
+ * short-circuit instead of walking soon-to-be-freed trigger state.
|
||||
+ */
|
||||
+ pcdev->pi_led_trigs = NULL;
|
||||
cancel_work_sync(&pcdev->ntf_work);
|
||||
kfifo_free(&pcdev->ntf_fifo);
|
||||
mutex_lock(&pse_list_mutex);
|
||||
@@ -1318,12 +1514,21 @@ static void pse_handle_events(struct pse
|
||||
{
|
||||
int i;
|
||||
|
||||
+ lockdep_assert_held(&pcdev->lock);
|
||||
+
|
||||
for_each_set_bit(i, notifs_mask, pcdev->nr_lines) {
|
||||
unsigned long pi_notifs, rnotifs;
|
||||
struct pse_ntf ntf = {};
|
||||
int ret;
|
||||
|
||||
- /* Do nothing PI not described */
|
||||
+ /* Update LEDs for described PIs regardless of consumer state.
|
||||
+ * LED triggers are registered at controller init, before any
|
||||
+ * PHY claims a PSE control, so rdev may still be NULL here.
|
||||
+ */
|
||||
+ if (pcdev->no_of_pse_pi || pcdev->pi[i].np)
|
||||
+ pse_led_update(pcdev, i);
|
||||
+
|
||||
+ /* Skip regulator/netlink path for PIs without consumers */
|
||||
if (!pcdev->pi[i].rdev)
|
||||
continue;
|
||||
|
||||
--- a/include/linux/pse-pd/pse.h
|
||||
+++ b/include/linux/pse-pd/pse.h
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/kfifo.h>
|
||||
#include <uapi/linux/ethtool.h>
|
||||
#include <uapi/linux/ethtool_netlink_generated.h>
|
||||
+#include <linux/leds.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
|
||||
/* Maximum current in uA according to IEEE 802.3-2022 Table 145-1 */
|
||||
@@ -268,6 +269,21 @@ struct pse_pi {
|
||||
};
|
||||
|
||||
/**
|
||||
+ * struct pse_pi_led_triggers - LED trigger state for a PSE PI
|
||||
+ *
|
||||
+ * @delivering: LED trigger for power delivering state
|
||||
+ * @enabled: LED trigger for admin enabled state
|
||||
+ * @last_delivering: cached delivering state for change detection
|
||||
+ * @last_enabled: cached enabled state for change detection
|
||||
+ */
|
||||
+struct pse_pi_led_triggers {
|
||||
+ struct led_trigger delivering;
|
||||
+ struct led_trigger enabled;
|
||||
+ bool last_delivering;
|
||||
+ bool last_enabled;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* struct pse_ntf - PSE notification element
|
||||
*
|
||||
* @id: ID of the PSE control
|
||||
@@ -305,6 +321,7 @@ struct pse_ntf {
|
||||
* @ntf_work: workqueue for PSE notification management
|
||||
* @ntf_fifo: PSE notifications FIFO
|
||||
* @ntf_fifo_lock: protect @ntf_fifo writer
|
||||
+ * @pi_led_trigs: per-PI LED trigger state array
|
||||
*/
|
||||
struct pse_controller_dev {
|
||||
const struct pse_controller_ops *ops;
|
||||
@@ -330,6 +347,7 @@ struct pse_controller_dev {
|
||||
struct work_struct ntf_work;
|
||||
DECLARE_KFIFO_PTR(ntf_fifo, struct pse_ntf);
|
||||
spinlock_t ntf_fifo_lock; /* Protect @ntf_fifo writer */
|
||||
+ struct pse_pi_led_triggers *pi_led_trigs;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -101,13 +101,6 @@ CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_CRYPTD=y
|
||||
CONFIG_CRYPTO_DEFLATE=y
|
||||
CONFIG_CRYPTO_DES=y
|
||||
CONFIG_CRYPTO_DEV_QCE=y
|
||||
# CONFIG_CRYPTO_DEV_QCE_ENABLE_AEAD is not set
|
||||
# CONFIG_CRYPTO_DEV_QCE_ENABLE_ALL is not set
|
||||
# CONFIG_CRYPTO_DEV_QCE_ENABLE_SHA is not set
|
||||
CONFIG_CRYPTO_DEV_QCE_ENABLE_SKCIPHER=y
|
||||
CONFIG_CRYPTO_DEV_QCE_SKCIPHER=y
|
||||
CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN=512
|
||||
CONFIG_CRYPTO_DEV_QCOM_RNG=y
|
||||
CONFIG_CRYPTO_DRBG=y
|
||||
CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Makefile for the IPQ ESS driver
|
||||
#
|
||||
|
||||
obj-$(CONFIG_QCOM_IPQ4019_ESS_EDMA) += ipq_ess.o
|
||||
|
||||
ipq_ess-objs := ipqess.o ipqess_ethtool.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,518 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0 OR ISC) */
|
||||
/* Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017 - 2018, John Crispin <john@phrozen.org>
|
||||
* Copyright (c) 2018 - 2019, Christian Lamparter <chunkeey@gmail.com>
|
||||
* Copyright (c) 2020 - 2021, Gabor Juhos <j4g8y7@gmail.com>
|
||||
* Copyright (c) 2021 - 2022, Maxime Chevallier <maxime.chevallier@bootlin.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IPQESS_H_
|
||||
#define _IPQESS_H_
|
||||
|
||||
#define IPQESS_NETDEV_QUEUES 4
|
||||
|
||||
#define IPQESS_TPD_EOP_SHIFT 31
|
||||
|
||||
#define IPQESS_PORT_ID_SHIFT 12
|
||||
#define IPQESS_PORT_ID_MASK 0x7
|
||||
|
||||
/* tpd word 3 bit 18-28 */
|
||||
#define IPQESS_TPD_PORT_BITMAP_SHIFT 18
|
||||
|
||||
#define IPQESS_TPD_FROM_CPU_SHIFT 25
|
||||
|
||||
#define IPQESS_RX_RING_SIZE 128
|
||||
#define IPQESS_RX_HEAD_BUFF_SIZE 1540
|
||||
#define IPQESS_TX_RING_SIZE 128
|
||||
#define IPQESS_MAX_RX_QUEUE 8
|
||||
#define IPQESS_MAX_TX_QUEUE 16
|
||||
|
||||
/* Configurations */
|
||||
#define IPQESS_INTR_CLEAR_TYPE 0
|
||||
#define IPQESS_INTR_SW_IDX_W_TYPE 0
|
||||
#define IPQESS_FIFO_THRESH_TYPE 0
|
||||
#define IPQESS_RSS_TYPE 0
|
||||
#define IPQESS_RX_IMT 0x0020
|
||||
#define IPQESS_TX_IMT 0x0050
|
||||
#define IPQESS_TPD_BURST 5
|
||||
#define IPQESS_TXF_BURST 0x100
|
||||
#define IPQESS_RFD_BURST 8
|
||||
#define IPQESS_RFD_THR 16
|
||||
#define IPQESS_RFD_LTHR 0
|
||||
|
||||
/* Flags used in transmit direction */
|
||||
#define IPQESS_DESC_LAST 0x1
|
||||
#define IPQESS_DESC_SINGLE 0x2
|
||||
#define IPQESS_DESC_PAGE 0x4
|
||||
|
||||
struct ipqess_statistics {
|
||||
u32 tx_q0_pkt;
|
||||
u32 tx_q1_pkt;
|
||||
u32 tx_q2_pkt;
|
||||
u32 tx_q3_pkt;
|
||||
u32 tx_q4_pkt;
|
||||
u32 tx_q5_pkt;
|
||||
u32 tx_q6_pkt;
|
||||
u32 tx_q7_pkt;
|
||||
u32 tx_q8_pkt;
|
||||
u32 tx_q9_pkt;
|
||||
u32 tx_q10_pkt;
|
||||
u32 tx_q11_pkt;
|
||||
u32 tx_q12_pkt;
|
||||
u32 tx_q13_pkt;
|
||||
u32 tx_q14_pkt;
|
||||
u32 tx_q15_pkt;
|
||||
u32 tx_q0_byte;
|
||||
u32 tx_q1_byte;
|
||||
u32 tx_q2_byte;
|
||||
u32 tx_q3_byte;
|
||||
u32 tx_q4_byte;
|
||||
u32 tx_q5_byte;
|
||||
u32 tx_q6_byte;
|
||||
u32 tx_q7_byte;
|
||||
u32 tx_q8_byte;
|
||||
u32 tx_q9_byte;
|
||||
u32 tx_q10_byte;
|
||||
u32 tx_q11_byte;
|
||||
u32 tx_q12_byte;
|
||||
u32 tx_q13_byte;
|
||||
u32 tx_q14_byte;
|
||||
u32 tx_q15_byte;
|
||||
u32 rx_q0_pkt;
|
||||
u32 rx_q1_pkt;
|
||||
u32 rx_q2_pkt;
|
||||
u32 rx_q3_pkt;
|
||||
u32 rx_q4_pkt;
|
||||
u32 rx_q5_pkt;
|
||||
u32 rx_q6_pkt;
|
||||
u32 rx_q7_pkt;
|
||||
u32 rx_q0_byte;
|
||||
u32 rx_q1_byte;
|
||||
u32 rx_q2_byte;
|
||||
u32 rx_q3_byte;
|
||||
u32 rx_q4_byte;
|
||||
u32 rx_q5_byte;
|
||||
u32 rx_q6_byte;
|
||||
u32 rx_q7_byte;
|
||||
u32 tx_desc_error;
|
||||
};
|
||||
|
||||
struct ipqess_tx_desc {
|
||||
__le16 len;
|
||||
__le16 svlan_tag;
|
||||
__le32 word1;
|
||||
__le32 addr;
|
||||
__le32 word3;
|
||||
} __aligned(16) __packed;
|
||||
|
||||
struct ipqess_rx_desc {
|
||||
__le16 rrd0;
|
||||
__le16 rrd1;
|
||||
__le16 rrd2;
|
||||
__le16 rrd3;
|
||||
__le16 rrd4;
|
||||
__le16 rrd5;
|
||||
__le16 rrd6;
|
||||
__le16 rrd7;
|
||||
} __aligned(16) __packed;
|
||||
|
||||
struct ipqess_buf {
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t dma;
|
||||
u32 flags;
|
||||
u16 length;
|
||||
};
|
||||
|
||||
struct ipqess_tx_ring {
|
||||
struct napi_struct napi_tx;
|
||||
u32 idx;
|
||||
int ring_id;
|
||||
struct ipqess *ess;
|
||||
struct netdev_queue *nq;
|
||||
struct ipqess_tx_desc *hw_desc;
|
||||
struct ipqess_buf *buf;
|
||||
dma_addr_t dma;
|
||||
u16 count;
|
||||
u16 head;
|
||||
u16 tail;
|
||||
};
|
||||
|
||||
struct ipqess_rx_ring {
|
||||
struct napi_struct napi_rx;
|
||||
u32 idx;
|
||||
int ring_id;
|
||||
struct ipqess *ess;
|
||||
struct device *ppdev;
|
||||
struct ipqess_rx_desc **hw_desc;
|
||||
struct ipqess_buf *buf;
|
||||
dma_addr_t dma;
|
||||
u16 head;
|
||||
u16 tail;
|
||||
atomic_t refill_count;
|
||||
};
|
||||
|
||||
struct ipqess_rx_ring_refill {
|
||||
struct ipqess_rx_ring *rx_ring;
|
||||
struct work_struct refill_work;
|
||||
};
|
||||
|
||||
#define IPQESS_IRQ_NAME_LEN 32
|
||||
|
||||
struct ipqess {
|
||||
struct net_device *netdev;
|
||||
void __iomem *hw_addr;
|
||||
|
||||
struct clk *ess_clk;
|
||||
struct reset_control *ess_rst;
|
||||
|
||||
struct ipqess_rx_ring rx_ring[IPQESS_NETDEV_QUEUES];
|
||||
|
||||
struct platform_device *pdev;
|
||||
struct phylink *phylink;
|
||||
struct phylink_config phylink_config;
|
||||
struct ipqess_tx_ring tx_ring[IPQESS_NETDEV_QUEUES];
|
||||
|
||||
struct ipqess_statistics ipqess_stats;
|
||||
|
||||
/* Protects stats */
|
||||
spinlock_t stats_lock;
|
||||
struct net_device_stats stats;
|
||||
|
||||
struct ipqess_rx_ring_refill rx_refill[IPQESS_NETDEV_QUEUES];
|
||||
u32 tx_irq[IPQESS_MAX_TX_QUEUE];
|
||||
char tx_irq_names[IPQESS_MAX_TX_QUEUE][IPQESS_IRQ_NAME_LEN];
|
||||
u32 rx_irq[IPQESS_MAX_RX_QUEUE];
|
||||
char rx_irq_names[IPQESS_MAX_TX_QUEUE][IPQESS_IRQ_NAME_LEN];
|
||||
};
|
||||
|
||||
void ipqess_set_ethtool_ops(struct net_device *netdev);
|
||||
void ipqess_update_hw_stats(struct ipqess *ess);
|
||||
|
||||
/* register definition */
|
||||
#define IPQESS_REG_MAS_CTRL 0x0
|
||||
#define IPQESS_REG_TIMEOUT_CTRL 0x004
|
||||
#define IPQESS_REG_DBG0 0x008
|
||||
#define IPQESS_REG_DBG1 0x00C
|
||||
#define IPQESS_REG_SW_CTRL0 0x100
|
||||
#define IPQESS_REG_SW_CTRL1 0x104
|
||||
|
||||
/* Interrupt Status Register */
|
||||
#define IPQESS_REG_RX_ISR 0x200
|
||||
#define IPQESS_REG_TX_ISR 0x208
|
||||
#define IPQESS_REG_MISC_ISR 0x210
|
||||
#define IPQESS_REG_WOL_ISR 0x218
|
||||
|
||||
#define IPQESS_MISC_ISR_RX_URG_Q(x) (1 << (x))
|
||||
|
||||
#define IPQESS_MISC_ISR_AXIR_TIMEOUT 0x00000100
|
||||
#define IPQESS_MISC_ISR_AXIR_ERR 0x00000200
|
||||
#define IPQESS_MISC_ISR_TXF_DEAD 0x00000400
|
||||
#define IPQESS_MISC_ISR_AXIW_ERR 0x00000800
|
||||
#define IPQESS_MISC_ISR_AXIW_TIMEOUT 0x00001000
|
||||
|
||||
#define IPQESS_WOL_ISR 0x00000001
|
||||
|
||||
/* Interrupt Mask Register */
|
||||
#define IPQESS_REG_MISC_IMR 0x214
|
||||
#define IPQESS_REG_WOL_IMR 0x218
|
||||
|
||||
#define IPQESS_RX_IMR_NORMAL_MASK 0x1
|
||||
#define IPQESS_TX_IMR_NORMAL_MASK 0x1
|
||||
#define IPQESS_MISC_IMR_NORMAL_MASK 0x80001FFF
|
||||
#define IPQESS_WOL_IMR_NORMAL_MASK 0x1
|
||||
|
||||
/* Edma receive consumer index */
|
||||
#define IPQESS_REG_RX_SW_CONS_IDX_Q(x) (0x220 + ((x) << 2)) /* x is the queue id */
|
||||
|
||||
/* Edma transmit consumer index */
|
||||
#define IPQESS_REG_TX_SW_CONS_IDX_Q(x) (0x240 + ((x) << 2)) /* x is the queue id */
|
||||
|
||||
/* IRQ Moderator Initial Timer Register */
|
||||
#define IPQESS_REG_IRQ_MODRT_TIMER_INIT 0x280
|
||||
#define IPQESS_IRQ_MODRT_TIMER_MASK 0xFFFF
|
||||
#define IPQESS_IRQ_MODRT_RX_TIMER_SHIFT 0
|
||||
#define IPQESS_IRQ_MODRT_TX_TIMER_SHIFT 16
|
||||
|
||||
/* Interrupt Control Register */
|
||||
#define IPQESS_REG_INTR_CTRL 0x284
|
||||
#define IPQESS_INTR_CLR_TYP_SHIFT 0
|
||||
#define IPQESS_INTR_SW_IDX_W_TYP_SHIFT 1
|
||||
#define IPQESS_INTR_CLEAR_TYPE_W1 0
|
||||
#define IPQESS_INTR_CLEAR_TYPE_R 1
|
||||
|
||||
/* RX Interrupt Mask Register */
|
||||
#define IPQESS_REG_RX_INT_MASK_Q(x) (0x300 + ((x) << 2)) /* x = queue id */
|
||||
|
||||
/* TX Interrupt mask register */
|
||||
#define IPQESS_REG_TX_INT_MASK_Q(x) (0x340 + ((x) << 2)) /* x = queue id */
|
||||
|
||||
/* Load Ptr Register
|
||||
* Software sets this bit after the initialization of the head and tail
|
||||
*/
|
||||
#define IPQESS_REG_TX_SRAM_PART 0x400
|
||||
#define IPQESS_LOAD_PTR_SHIFT 16
|
||||
|
||||
/* TXQ Control Register */
|
||||
#define IPQESS_REG_TXQ_CTRL 0x404
|
||||
#define IPQESS_TXQ_CTRL_IP_OPTION_EN 0x10
|
||||
#define IPQESS_TXQ_CTRL_TXQ_EN 0x20
|
||||
#define IPQESS_TXQ_CTRL_ENH_MODE 0x40
|
||||
#define IPQESS_TXQ_CTRL_LS_8023_EN 0x80
|
||||
#define IPQESS_TXQ_CTRL_TPD_BURST_EN 0x100
|
||||
#define IPQESS_TXQ_CTRL_LSO_BREAK_EN 0x200
|
||||
#define IPQESS_TXQ_NUM_TPD_BURST_MASK 0xF
|
||||
#define IPQESS_TXQ_TXF_BURST_NUM_MASK 0xFFFF
|
||||
#define IPQESS_TXQ_NUM_TPD_BURST_SHIFT 0
|
||||
#define IPQESS_TXQ_TXF_BURST_NUM_SHIFT 16
|
||||
|
||||
#define IPQESS_REG_TXF_WATER_MARK 0x408 /* In 8-bytes */
|
||||
#define IPQESS_TXF_WATER_MARK_MASK 0x0FFF
|
||||
#define IPQESS_TXF_LOW_WATER_MARK_SHIFT 0
|
||||
#define IPQESS_TXF_HIGH_WATER_MARK_SHIFT 16
|
||||
#define IPQESS_TXQ_CTRL_BURST_MODE_EN 0x80000000
|
||||
|
||||
/* WRR Control Register */
|
||||
#define IPQESS_REG_WRR_CTRL_Q0_Q3 0x40c
|
||||
#define IPQESS_REG_WRR_CTRL_Q4_Q7 0x410
|
||||
#define IPQESS_REG_WRR_CTRL_Q8_Q11 0x414
|
||||
#define IPQESS_REG_WRR_CTRL_Q12_Q15 0x418
|
||||
|
||||
/* Weight round robin(WRR), it takes queue as input, and computes
|
||||
* starting bits where we need to write the weight for a particular
|
||||
* queue
|
||||
*/
|
||||
#define IPQESS_WRR_SHIFT(x) (((x) * 5) % 20)
|
||||
|
||||
/* Tx Descriptor Control Register */
|
||||
#define IPQESS_REG_TPD_RING_SIZE 0x41C
|
||||
#define IPQESS_TPD_RING_SIZE_SHIFT 0
|
||||
#define IPQESS_TPD_RING_SIZE_MASK 0xFFFF
|
||||
|
||||
/* Transmit descriptor base address */
|
||||
#define IPQESS_REG_TPD_BASE_ADDR_Q(x) (0x420 + ((x) << 2)) /* x = queue id */
|
||||
|
||||
/* TPD Index Register */
|
||||
#define IPQESS_REG_TPD_IDX_Q(x) (0x460 + ((x) << 2)) /* x = queue id */
|
||||
|
||||
#define IPQESS_TPD_PROD_IDX_BITS 0x0000FFFF
|
||||
#define IPQESS_TPD_CONS_IDX_BITS 0xFFFF0000
|
||||
#define IPQESS_TPD_PROD_IDX_MASK 0xFFFF
|
||||
#define IPQESS_TPD_CONS_IDX_MASK 0xFFFF
|
||||
#define IPQESS_TPD_PROD_IDX_SHIFT 0
|
||||
#define IPQESS_TPD_CONS_IDX_SHIFT 16
|
||||
|
||||
/* TX Virtual Queue Mapping Control Register */
|
||||
#define IPQESS_REG_VQ_CTRL0 0x4A0
|
||||
#define IPQESS_REG_VQ_CTRL1 0x4A4
|
||||
|
||||
/* Virtual QID shift, it takes queue as input, and computes
|
||||
* Virtual QID position in virtual qid control register
|
||||
*/
|
||||
#define IPQESS_VQ_ID_SHIFT(i) (((i) * 3) % 24)
|
||||
|
||||
/* Virtual Queue Default Value */
|
||||
#define IPQESS_VQ_REG_VALUE 0x240240
|
||||
|
||||
/* Tx side Port Interface Control Register */
|
||||
#define IPQESS_REG_PORT_CTRL 0x4A8
|
||||
#define IPQESS_PAD_EN_SHIFT 15
|
||||
|
||||
/* Tx side VLAN Configuration Register */
|
||||
#define IPQESS_REG_VLAN_CFG 0x4AC
|
||||
|
||||
#define IPQESS_VLAN_CFG_SVLAN_TPID_SHIFT 0
|
||||
#define IPQESS_VLAN_CFG_SVLAN_TPID_MASK 0xffff
|
||||
#define IPQESS_VLAN_CFG_CVLAN_TPID_SHIFT 16
|
||||
#define IPQESS_VLAN_CFG_CVLAN_TPID_MASK 0xffff
|
||||
|
||||
#define IPQESS_TX_CVLAN 16
|
||||
#define IPQESS_TX_INS_CVLAN 17
|
||||
#define IPQESS_TX_CVLAN_TAG_SHIFT 0
|
||||
|
||||
#define IPQESS_TX_SVLAN 14
|
||||
#define IPQESS_TX_INS_SVLAN 15
|
||||
#define IPQESS_TX_SVLAN_TAG_SHIFT 16
|
||||
|
||||
/* Tx Queue Packet Statistic Register */
|
||||
#define IPQESS_REG_TX_STAT_PKT_Q(x) (0x700 + ((x) << 3)) /* x = queue id */
|
||||
|
||||
#define IPQESS_TX_STAT_PKT_MASK 0xFFFFFF
|
||||
|
||||
/* Tx Queue Byte Statistic Register */
|
||||
#define IPQESS_REG_TX_STAT_BYTE_Q(x) (0x704 + ((x) << 3)) /* x = queue id */
|
||||
|
||||
/* Load Balance Based Ring Offset Register */
|
||||
#define IPQESS_REG_LB_RING 0x800
|
||||
#define IPQESS_LB_RING_ENTRY_MASK 0xff
|
||||
#define IPQESS_LB_RING_ID_MASK 0x7
|
||||
#define IPQESS_LB_RING_PROFILE_ID_MASK 0x3
|
||||
#define IPQESS_LB_RING_ENTRY_BIT_OFFSET 8
|
||||
#define IPQESS_LB_RING_ID_OFFSET 0
|
||||
#define IPQESS_LB_RING_PROFILE_ID_OFFSET 3
|
||||
#define IPQESS_LB_REG_VALUE 0x6040200
|
||||
|
||||
/* Load Balance Priority Mapping Register */
|
||||
#define IPQESS_REG_LB_PRI_START 0x804
|
||||
#define IPQESS_REG_LB_PRI_END 0x810
|
||||
#define IPQESS_LB_PRI_REG_INC 4
|
||||
#define IPQESS_LB_PRI_ENTRY_BIT_OFFSET 4
|
||||
#define IPQESS_LB_PRI_ENTRY_MASK 0xf
|
||||
|
||||
/* RSS Priority Mapping Register */
|
||||
#define IPQESS_REG_RSS_PRI 0x820
|
||||
#define IPQESS_RSS_PRI_ENTRY_MASK 0xf
|
||||
#define IPQESS_RSS_RING_ID_MASK 0x7
|
||||
#define IPQESS_RSS_PRI_ENTRY_BIT_OFFSET 4
|
||||
|
||||
/* RSS Indirection Register */
|
||||
#define IPQESS_REG_RSS_IDT(x) (0x840 + ((x) << 2)) /* x = No. of indirection table */
|
||||
#define IPQESS_NUM_IDT 16
|
||||
#define IPQESS_RSS_IDT_VALUE 0x64206420
|
||||
|
||||
/* Default RSS Ring Register */
|
||||
#define IPQESS_REG_DEF_RSS 0x890
|
||||
#define IPQESS_DEF_RSS_MASK 0x7
|
||||
|
||||
/* RSS Hash Function Type Register */
|
||||
#define IPQESS_REG_RSS_TYPE 0x894
|
||||
#define IPQESS_RSS_TYPE_NONE 0x01
|
||||
#define IPQESS_RSS_TYPE_IPV4TCP 0x02
|
||||
#define IPQESS_RSS_TYPE_IPV6_TCP 0x04
|
||||
#define IPQESS_RSS_TYPE_IPV4_UDP 0x08
|
||||
#define IPQESS_RSS_TYPE_IPV6UDP 0x10
|
||||
#define IPQESS_RSS_TYPE_IPV4 0x20
|
||||
#define IPQESS_RSS_TYPE_IPV6 0x40
|
||||
#define IPQESS_RSS_HASH_MODE_MASK 0x7f
|
||||
|
||||
#define IPQESS_REG_RSS_HASH_VALUE 0x8C0
|
||||
|
||||
#define IPQESS_REG_RSS_TYPE_RESULT 0x8C4
|
||||
|
||||
#define IPQESS_HASH_TYPE_START 0
|
||||
#define IPQESS_HASH_TYPE_END 5
|
||||
#define IPQESS_HASH_TYPE_SHIFT 12
|
||||
|
||||
#define IPQESS_RFS_FLOW_ENTRIES 1024
|
||||
#define IPQESS_RFS_FLOW_ENTRIES_MASK (IPQESS_RFS_FLOW_ENTRIES - 1)
|
||||
#define IPQESS_RFS_EXPIRE_COUNT_PER_CALL 128
|
||||
|
||||
/* RFD Base Address Register */
|
||||
#define IPQESS_REG_RFD_BASE_ADDR_Q(x) (0x950 + ((x) << 2)) /* x = queue id */
|
||||
|
||||
/* RFD Index Register */
|
||||
#define IPQESS_REG_RFD_IDX_Q(x) (0x9B0 + ((x) << 2)) /* x = queue id */
|
||||
|
||||
#define IPQESS_RFD_PROD_IDX_BITS 0x00000FFF
|
||||
#define IPQESS_RFD_CONS_IDX_BITS 0x0FFF0000
|
||||
#define IPQESS_RFD_PROD_IDX_MASK 0xFFF
|
||||
#define IPQESS_RFD_CONS_IDX_MASK 0xFFF
|
||||
#define IPQESS_RFD_PROD_IDX_SHIFT 0
|
||||
#define IPQESS_RFD_CONS_IDX_SHIFT 16
|
||||
|
||||
/* Rx Descriptor Control Register */
|
||||
#define IPQESS_REG_RX_DESC0 0xA10
|
||||
#define IPQESS_RFD_RING_SIZE_MASK 0xFFF
|
||||
#define IPQESS_RX_BUF_SIZE_MASK 0xFFFF
|
||||
#define IPQESS_RFD_RING_SIZE_SHIFT 0
|
||||
#define IPQESS_RX_BUF_SIZE_SHIFT 16
|
||||
|
||||
#define IPQESS_REG_RX_DESC1 0xA14
|
||||
#define IPQESS_RXQ_RFD_BURST_NUM_MASK 0x3F
|
||||
#define IPQESS_RXQ_RFD_PF_THRESH_MASK 0x1F
|
||||
#define IPQESS_RXQ_RFD_LOW_THRESH_MASK 0xFFF
|
||||
#define IPQESS_RXQ_RFD_BURST_NUM_SHIFT 0
|
||||
#define IPQESS_RXQ_RFD_PF_THRESH_SHIFT 8
|
||||
#define IPQESS_RXQ_RFD_LOW_THRESH_SHIFT 16
|
||||
|
||||
/* RXQ Control Register */
|
||||
#define IPQESS_REG_RXQ_CTRL 0xA18
|
||||
#define IPQESS_FIFO_THRESH_TYPE_SHIF 0
|
||||
#define IPQESS_FIFO_THRESH_128_BYTE 0x0
|
||||
#define IPQESS_FIFO_THRESH_64_BYTE 0x1
|
||||
#define IPQESS_RXQ_CTRL_RMV_VLAN 0x00000002
|
||||
#define IPQESS_RXQ_CTRL_EN_MASK GENMASK(15, 8)
|
||||
#define IPQESS_RXQ_CTRL_EN(__qid) BIT(8 + (__qid))
|
||||
|
||||
/* AXI Burst Size Config */
|
||||
#define IPQESS_REG_AXIW_CTRL_MAXWRSIZE 0xA1C
|
||||
#define IPQESS_AXIW_MAXWRSIZE_VALUE 0x0
|
||||
|
||||
/* Rx Statistics Register */
|
||||
#define IPQESS_REG_RX_STAT_BYTE_Q(x) (0xA30 + ((x) << 2)) /* x = queue id */
|
||||
#define IPQESS_REG_RX_STAT_PKT_Q(x) (0xA50 + ((x) << 2)) /* x = queue id */
|
||||
|
||||
/* WoL Pattern Length Register */
|
||||
#define IPQESS_REG_WOL_PATTERN_LEN0 0xC00
|
||||
#define IPQESS_WOL_PT_LEN_MASK 0xFF
|
||||
#define IPQESS_WOL_PT0_LEN_SHIFT 0
|
||||
#define IPQESS_WOL_PT1_LEN_SHIFT 8
|
||||
#define IPQESS_WOL_PT2_LEN_SHIFT 16
|
||||
#define IPQESS_WOL_PT3_LEN_SHIFT 24
|
||||
|
||||
#define IPQESS_REG_WOL_PATTERN_LEN1 0xC04
|
||||
#define IPQESS_WOL_PT4_LEN_SHIFT 0
|
||||
#define IPQESS_WOL_PT5_LEN_SHIFT 8
|
||||
#define IPQESS_WOL_PT6_LEN_SHIFT 16
|
||||
|
||||
/* WoL Control Register */
|
||||
#define IPQESS_REG_WOL_CTRL 0xC08
|
||||
#define IPQESS_WOL_WK_EN 0x00000001
|
||||
#define IPQESS_WOL_MG_EN 0x00000002
|
||||
#define IPQESS_WOL_PT0_EN 0x00000004
|
||||
#define IPQESS_WOL_PT1_EN 0x00000008
|
||||
#define IPQESS_WOL_PT2_EN 0x00000010
|
||||
#define IPQESS_WOL_PT3_EN 0x00000020
|
||||
#define IPQESS_WOL_PT4_EN 0x00000040
|
||||
#define IPQESS_WOL_PT5_EN 0x00000080
|
||||
#define IPQESS_WOL_PT6_EN 0x00000100
|
||||
|
||||
/* MAC Control Register */
|
||||
#define IPQESS_REG_MAC_CTRL0 0xC20
|
||||
#define IPQESS_REG_MAC_CTRL1 0xC24
|
||||
|
||||
/* WoL Pattern Register */
|
||||
#define IPQESS_REG_WOL_PATTERN_START 0x5000
|
||||
#define IPQESS_PATTERN_PART_REG_OFFSET 0x40
|
||||
|
||||
/* TX descriptor fields */
|
||||
#define IPQESS_TPD_HDR_SHIFT 0
|
||||
#define IPQESS_TPD_PPPOE_EN 0x00000100
|
||||
#define IPQESS_TPD_IP_CSUM_EN 0x00000200
|
||||
#define IPQESS_TPD_TCP_CSUM_EN 0x0000400
|
||||
#define IPQESS_TPD_UDP_CSUM_EN 0x00000800
|
||||
#define IPQESS_TPD_CUSTOM_CSUM_EN 0x00000C00
|
||||
#define IPQESS_TPD_LSO_EN 0x00001000
|
||||
#define IPQESS_TPD_LSO_V2_EN 0x00002000
|
||||
/* The VLAN_TAGGED bit is not used in the publicly available
|
||||
* drivers. The definition has been stolen from the Atheros
|
||||
* 'alx' driver (drivers/net/ethernet/atheros/alx/hw.h). It
|
||||
* seems that it has the same meaning in regard to the EDMA
|
||||
* hardware.
|
||||
*/
|
||||
#define IPQESS_TPD_VLAN_TAGGED 0x00004000
|
||||
#define IPQESS_TPD_IPV4_EN 0x00010000
|
||||
#define IPQESS_TPD_MSS_MASK 0x1FFF
|
||||
#define IPQESS_TPD_MSS_SHIFT 18
|
||||
#define IPQESS_TPD_CUSTOM_CSUM_SHIFT 18
|
||||
|
||||
/* RRD descriptor fields */
|
||||
#define IPQESS_RRD_NUM_RFD_MASK 0x000F
|
||||
#define IPQESS_RRD_PKT_SIZE_MASK 0x3FFF
|
||||
#define IPQESS_RRD_SRC_PORT_NUM_MASK 0x4000
|
||||
#define IPQESS_RRD_SVLAN 0x8000
|
||||
#define IPQESS_RRD_FLOW_COOKIE_MASK 0x07FF
|
||||
|
||||
#define IPQESS_RRD_PKT_SIZE_MASK 0x3FFF
|
||||
#define IPQESS_RRD_CSUM_FAIL_MASK 0xC000
|
||||
#define IPQESS_RRD_CVLAN 0x0001
|
||||
#define IPQESS_RRD_DESC_VALID 0x8000
|
||||
|
||||
#define IPQESS_RRD_PRIORITY_SHIFT 4
|
||||
#define IPQESS_RRD_PRIORITY_MASK 0x7
|
||||
#define IPQESS_RRD_PORT_TYPE_SHIFT 7
|
||||
#define IPQESS_RRD_PORT_TYPE_MASK 0x1F
|
||||
|
||||
#define IPQESS_RRD_PORT_ID_MASK 0x7000
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR ISC
|
||||
/* Copyright (c) 2015 - 2016, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017 - 2018, John Crispin <john@phrozen.org>
|
||||
* Copyright (c) 2021 - 2022, Maxime Chevallier <maxime.chevallier@bootlin.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/phylink.h>
|
||||
|
||||
#include "ipqess.h"
|
||||
|
||||
struct ipqess_ethtool_stats {
|
||||
u8 string[ETH_GSTRING_LEN];
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
#define IPQESS_STAT(m) offsetof(struct ipqess_statistics, m)
|
||||
#define DRVINFO_LEN 32
|
||||
|
||||
static const struct ipqess_ethtool_stats ipqess_stats[] = {
|
||||
{"tx_q0_pkt", IPQESS_STAT(tx_q0_pkt)},
|
||||
{"tx_q1_pkt", IPQESS_STAT(tx_q1_pkt)},
|
||||
{"tx_q2_pkt", IPQESS_STAT(tx_q2_pkt)},
|
||||
{"tx_q3_pkt", IPQESS_STAT(tx_q3_pkt)},
|
||||
{"tx_q4_pkt", IPQESS_STAT(tx_q4_pkt)},
|
||||
{"tx_q5_pkt", IPQESS_STAT(tx_q5_pkt)},
|
||||
{"tx_q6_pkt", IPQESS_STAT(tx_q6_pkt)},
|
||||
{"tx_q7_pkt", IPQESS_STAT(tx_q7_pkt)},
|
||||
{"tx_q8_pkt", IPQESS_STAT(tx_q8_pkt)},
|
||||
{"tx_q9_pkt", IPQESS_STAT(tx_q9_pkt)},
|
||||
{"tx_q10_pkt", IPQESS_STAT(tx_q10_pkt)},
|
||||
{"tx_q11_pkt", IPQESS_STAT(tx_q11_pkt)},
|
||||
{"tx_q12_pkt", IPQESS_STAT(tx_q12_pkt)},
|
||||
{"tx_q13_pkt", IPQESS_STAT(tx_q13_pkt)},
|
||||
{"tx_q14_pkt", IPQESS_STAT(tx_q14_pkt)},
|
||||
{"tx_q15_pkt", IPQESS_STAT(tx_q15_pkt)},
|
||||
{"tx_q0_byte", IPQESS_STAT(tx_q0_byte)},
|
||||
{"tx_q1_byte", IPQESS_STAT(tx_q1_byte)},
|
||||
{"tx_q2_byte", IPQESS_STAT(tx_q2_byte)},
|
||||
{"tx_q3_byte", IPQESS_STAT(tx_q3_byte)},
|
||||
{"tx_q4_byte", IPQESS_STAT(tx_q4_byte)},
|
||||
{"tx_q5_byte", IPQESS_STAT(tx_q5_byte)},
|
||||
{"tx_q6_byte", IPQESS_STAT(tx_q6_byte)},
|
||||
{"tx_q7_byte", IPQESS_STAT(tx_q7_byte)},
|
||||
{"tx_q8_byte", IPQESS_STAT(tx_q8_byte)},
|
||||
{"tx_q9_byte", IPQESS_STAT(tx_q9_byte)},
|
||||
{"tx_q10_byte", IPQESS_STAT(tx_q10_byte)},
|
||||
{"tx_q11_byte", IPQESS_STAT(tx_q11_byte)},
|
||||
{"tx_q12_byte", IPQESS_STAT(tx_q12_byte)},
|
||||
{"tx_q13_byte", IPQESS_STAT(tx_q13_byte)},
|
||||
{"tx_q14_byte", IPQESS_STAT(tx_q14_byte)},
|
||||
{"tx_q15_byte", IPQESS_STAT(tx_q15_byte)},
|
||||
{"rx_q0_pkt", IPQESS_STAT(rx_q0_pkt)},
|
||||
{"rx_q1_pkt", IPQESS_STAT(rx_q1_pkt)},
|
||||
{"rx_q2_pkt", IPQESS_STAT(rx_q2_pkt)},
|
||||
{"rx_q3_pkt", IPQESS_STAT(rx_q3_pkt)},
|
||||
{"rx_q4_pkt", IPQESS_STAT(rx_q4_pkt)},
|
||||
{"rx_q5_pkt", IPQESS_STAT(rx_q5_pkt)},
|
||||
{"rx_q6_pkt", IPQESS_STAT(rx_q6_pkt)},
|
||||
{"rx_q7_pkt", IPQESS_STAT(rx_q7_pkt)},
|
||||
{"rx_q0_byte", IPQESS_STAT(rx_q0_byte)},
|
||||
{"rx_q1_byte", IPQESS_STAT(rx_q1_byte)},
|
||||
{"rx_q2_byte", IPQESS_STAT(rx_q2_byte)},
|
||||
{"rx_q3_byte", IPQESS_STAT(rx_q3_byte)},
|
||||
{"rx_q4_byte", IPQESS_STAT(rx_q4_byte)},
|
||||
{"rx_q5_byte", IPQESS_STAT(rx_q5_byte)},
|
||||
{"rx_q6_byte", IPQESS_STAT(rx_q6_byte)},
|
||||
{"rx_q7_byte", IPQESS_STAT(rx_q7_byte)},
|
||||
{"tx_desc_error", IPQESS_STAT(tx_desc_error)},
|
||||
};
|
||||
|
||||
static int ipqess_get_strset_count(struct net_device *netdev, int sset)
|
||||
{
|
||||
switch (sset) {
|
||||
case ETH_SS_STATS:
|
||||
return ARRAY_SIZE(ipqess_stats);
|
||||
default:
|
||||
netdev_dbg(netdev, "%s: Unsupported string set", __func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void ipqess_get_strings(struct net_device *netdev, u32 stringset,
|
||||
u8 *data)
|
||||
{
|
||||
u8 *p = data;
|
||||
u32 i;
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
for (i = 0; i < ARRAY_SIZE(ipqess_stats); i++)
|
||||
ethtool_puts(&p, ipqess_stats[i].string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ipqess_get_ethtool_stats(struct net_device *netdev,
|
||||
struct ethtool_stats *stats,
|
||||
uint64_t *data)
|
||||
{
|
||||
struct ipqess *ess = netdev_priv(netdev);
|
||||
u32 *essstats = (u32 *)&ess->ipqess_stats;
|
||||
int i;
|
||||
|
||||
spin_lock(&ess->stats_lock);
|
||||
|
||||
ipqess_update_hw_stats(ess);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ipqess_stats); i++)
|
||||
data[i] = *(u32 *)(essstats + (ipqess_stats[i].offset / sizeof(u32)));
|
||||
|
||||
spin_unlock(&ess->stats_lock);
|
||||
}
|
||||
|
||||
static void ipqess_get_drvinfo(struct net_device *dev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
strscpy(info->driver, "qca_ipqess", DRVINFO_LEN);
|
||||
strscpy(info->bus_info, "axi", ETHTOOL_BUSINFO_LEN);
|
||||
}
|
||||
|
||||
static int ipqess_get_link_ksettings(struct net_device *netdev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct ipqess *ess = netdev_priv(netdev);
|
||||
|
||||
return phylink_ethtool_ksettings_get(ess->phylink, cmd);
|
||||
}
|
||||
|
||||
static int ipqess_set_link_ksettings(struct net_device *netdev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct ipqess *ess = netdev_priv(netdev);
|
||||
|
||||
return phylink_ethtool_ksettings_set(ess->phylink, cmd);
|
||||
}
|
||||
|
||||
static void ipqess_get_ringparam(struct net_device *netdev,
|
||||
struct ethtool_ringparam *ring,
|
||||
struct kernel_ethtool_ringparam *kernel_ering,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
ring->tx_max_pending = IPQESS_TX_RING_SIZE;
|
||||
ring->rx_max_pending = IPQESS_RX_RING_SIZE;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops ipqesstool_ops = {
|
||||
.get_drvinfo = &ipqess_get_drvinfo,
|
||||
.get_link = ðtool_op_get_link,
|
||||
.get_link_ksettings = &ipqess_get_link_ksettings,
|
||||
.set_link_ksettings = &ipqess_set_link_ksettings,
|
||||
.get_strings = &ipqess_get_strings,
|
||||
.get_sset_count = &ipqess_get_strset_count,
|
||||
.get_ethtool_stats = &ipqess_get_ethtool_stats,
|
||||
.get_ringparam = ipqess_get_ringparam,
|
||||
};
|
||||
|
||||
void ipqess_set_ethtool_ops(struct net_device *netdev)
|
||||
{
|
||||
netdev->ethtool_ops = &ipqesstool_ops;
|
||||
}
|
||||
+5
-1963
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -64,7 +64,7 @@ Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -21146,6 +21146,7 @@ L: netdev@vger.kernel.org
|
||||
@@ -21145,6 +21145,7 @@ L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/qcom,ipq4019-ess-edma.yaml
|
||||
F: drivers/net/ethernet/qualcomm/ipqess/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user