Merge remote-tracking branch 'immortalwrt/master' into k6.12-nss

This commit is contained in:
Roc Lai 2025-09-30 19:43:57 +08:00
commit 1448544b09
73 changed files with 1400 additions and 802 deletions

View File

@ -519,7 +519,7 @@ define Build/yaffs-filesystem
filesystem_size="filesystem_blocks * 64 * 1024" \
filesystem_size_with_reserve="(filesystem_blocks + 2) * 64 * 1024"; \
head -c $$filesystem_size_with_reserve /dev/zero | tr "\000" "\377" > $@.img \
&& yafut -d $@.img -w -i $@ -o kernel -C 1040 -B 64k -E -P -S $(1) \
&& yafut -d $@.img -w -i $@ -o $(if $(findstring v7,$@),bootimage,kernel) -C 1040 -B 64k -E -P -S $(1) \
&& truncate -s $$filesystem_size $@.img \
&& mv $@.img $@
endef
@ -557,6 +557,11 @@ define Build/gl-qsdk-factory
$(KDIR_TMP)/$(notdir $(BOOT_SCRIPT))
endef
define Build/kernel-pack-npk
$(STAGING_DIR_HOST)/bin/npk_pack_kernel $@ $@.npk
mv $@.npk $@
endef
define Build/linksys-image
let \
size="$$(stat -c%s $@)" \

View File

@ -595,7 +595,6 @@ define Device/Check/Common
_PROFILE_SET :=
endif
endif
DEVICE_PACKAGES += $$(call extra_packages,$$(DEVICE_PACKAGES))
ifdef TARGET_PER_DEVICE_ROOTFS
$$(eval $$(call merge_packages,_PACKAGES,$$(DEVICE_PACKAGES) $$(call DEVICE_EXTRA_PACKAGES,$(1))))
ROOTFS_ID/$(1) := $$(if $$(_PROFILE_SET),$$(call mkfs_packages_id,$$(_PACKAGES)))

View File

@ -64,13 +64,8 @@ DEFAULT_PACKAGES.tweak:=\
block-mount \
default-settings-chn \
kmod-nf-nathelper \
kmod-nf-nathelper-extra \
luci-light \
luci-app-cpufreq \
luci-app-package-manager \
luci-compat \
luci-lib-base \
luci-lib-ipkg
luci \
luci-app-cpufreq
ifneq ($(DUMP),)
all: dumpinfo
@ -121,13 +116,6 @@ DEFAULT_PACKAGES += $(DEFAULT_PACKAGES.$(DEVICE_TYPE))
##
filter_packages = $(filter-out -% $(patsubst -%,%,$(filter -%,$(1))),$(1))
##@
# @brief Append extra package dependencies.
#
# @param 1: Package list.
##
extra_packages = $(if $(filter wpad wpad-% nas,$(1)),iwinfo)
define ProfileDefault
NAME:=
PRIORITY:=
@ -144,7 +132,7 @@ define Profile
echo "Target-Profile: $(1)"; \
$(if $(PRIORITY), echo "Target-Profile-Priority: $(PRIORITY)"; ) \
echo "Target-Profile-Name: $(NAME)"; \
echo "Target-Profile-Packages: $(PACKAGES) $(call extra_packages,$(DEFAULT_PACKAGES) $(PACKAGES))"; \
echo "Target-Profile-Packages: $(PACKAGES)"; \
echo "Target-Profile-Description:"; \
echo "$$$$$$$$$(call shvar,Profile/$(1)/Description)"; \
echo "@@"; \
@ -402,7 +390,7 @@ define BuildTargets/DumpCurrent
echo "$$$$DESCRIPTION"; \
echo '@@'; \
$(if $(DEFAULT_PROFILE),echo 'Target-Default-Profile: $(DEFAULT_PROFILE)';) \
echo 'Default-Packages: $(DEFAULT_PACKAGES) $(call extra_packages,$(DEFAULT_PACKAGES))'; \
echo 'Default-Packages: $(DEFAULT_PACKAGES)'; \
$(DUMPINFO)
$(if $(CUR_SUBTARGET),$(SUBMAKE) -r --no-print-directory -C image -s DUMP=1 SUBTARGET=$(CUR_SUBTARGET))
$(if $(SUBTARGET),,@$(foreach SUBTARGET,$(SUBTARGETS),$(SUBMAKE) --no-print-directory -s DUMP=1 SUBTARGET=$(SUBTARGET); ))

View File

@ -287,7 +287,7 @@ define U-Boot/mt7981_cmcc_rax3000me-emmc-ddr3
UBOOT_IMAGE:=u-boot.fip
BL2_BOOTDEV:=emmc
BL2_SOC:=mt7981
BL2_DDRTYPE:=ddr3
BL2_DDRTYPE:=ddr3-1866mhz
DEPENDS:=+trusted-firmware-a-mt7981-emmc-ddr3-1866mhz
endef
@ -311,7 +311,7 @@ define U-Boot/mt7981_cmcc_rax3000me-nand-ddr3
UBOOT_IMAGE:=u-boot.fip
BL2_BOOTDEV:=spim-nand
BL2_SOC:=mt7981
BL2_DDRTYPE:=ddr3
BL2_DDRTYPE:=ddr3-1866mhz
DEPENDS:=+trusted-firmware-a-mt7981-spim-nand-ddr3-1866mhz
endef

View File

@ -567,7 +567,7 @@ define KernelPackage/phy-aeonsemi-as21xxx
AUTOLOAD:=$(call AutoLoad,18,as21xxx)
endef
define KernelPackage/phy-aeonsemi-as21x1x/description
define KernelPackage/phy-aeonsemi-as21xxx/description
Kernel modules for Aeonsemi AS21x1x 10G Ethernet PHY
endef

View File

@ -250,6 +250,7 @@ function setup() {
break;
// fallthrough
case 'sta':
data.ap_start_disabled = true;
let config = supplicant.generate(supplicant_data, data, v);
if (mode == "mesh")
config_add_mesh_params(config, v.config);

View File

@ -1077,15 +1077,6 @@
"description": "If bridge parameter is set, the WDS STA interface will be added to the same bridge by default",
"type": "boolean"
},
"wmm": {
"type": "alias",
"default": "wmm_enabled"
},
"wmm_enabled": {
"description": "Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e)",
"type": "boolean",
"default": true
},
"wnm_sleep_mode": {
"description": "WNM-Sleep Mode (extended sleep mode for stations)",
"type": "boolean"

View File

@ -45,6 +45,7 @@ function iface_setup(config) {
append('bssid', config.macaddr);
config.ssid2 = config.ssid;
config.wmm_enabled = 1;
append_string_vars(config, [ 'ssid2' ]);
append_vars(config, [
@ -53,9 +54,9 @@ function iface_setup(config) {
'disassoc_low_ack', 'skip_inactivity_poll', 'ignore_broadcast_ssid', 'uapsd_advertisement_enabled',
'utf8_ssid', 'multi_ap', 'tdls_prohibit', 'bridge', 'wds_sta', 'wds_bridge',
'snoop_iface', 'vendor_elements', 'nas_identifier', 'radius_acct_interim_interval',
'ocv', 'multicast_to_unicast', 'preamble', 'wmm_enabled', 'proxy_arp', 'per_sta_vif', 'mbo',
'ocv', 'multicast_to_unicast', 'preamble', 'proxy_arp', 'per_sta_vif', 'mbo',
'bss_transition', 'wnm_sleep_mode', 'wnm_sleep_mode_no_keys', 'qos_map_set', 'max_listen_int',
'dtim_period',
'dtim_period', 'wmm_enabled', 'start_disabled',
]);
}
@ -433,6 +434,7 @@ export function generate(interface, data, config, vlans, stas, phy_features) {
iface_stations(config, stas);
config.start_disabled = data.ap_start_disabled;
iface_setup(config);
iface.parse_encryption(config, data.config);

View File

@ -275,7 +275,7 @@ EOF
hostapd_common_add_bss_config() {
config_add_string 'bssid:macaddr' 'ssid:string'
config_add_boolean wds wmm uapsd hidden utf8_ssid ppsk
config_add_boolean wds uapsd hidden utf8_ssid ppsk
config_add_int maxassoc max_inactivity
config_add_boolean disassoc_low_ack isolate short_preamble skip_inactivity_poll
@ -548,7 +548,7 @@ hostapd_set_bss_options() {
maxassoc max_inactivity disassoc_low_ack isolate auth_cache \
wps_pushbutton wps_label ext_registrar wps_pbc_in_m1 wps_ap_setup_locked \
wps_independent wps_device_type wps_device_name wps_manufacturer wps_pin \
macfilter ssid utf8_ssid wmm uapsd hidden short_preamble rsn_preauth \
macfilter ssid utf8_ssid uapsd hidden short_preamble rsn_preauth \
iapp_interface eapol_version dynamic_vlan ieee80211w nasid \
acct_secret acct_port acct_interval \
bss_load_update_period chan_util_avg_period sae_require_mfp sae_pwe \
@ -567,7 +567,6 @@ hostapd_set_bss_options() {
set_default disassoc_low_ack 1
set_default skip_inactivity_poll 0
set_default hidden 0
set_default wmm 1
set_default uapsd 1
set_default wpa_disable_eapol_key_retries 0
set_default tdls_prohibit 0
@ -605,7 +604,7 @@ hostapd_set_bss_options() {
append bss_conf "disassoc_low_ack=$disassoc_low_ack" "$N"
append bss_conf "skip_inactivity_poll=$skip_inactivity_poll" "$N"
append bss_conf "preamble=$short_preamble" "$N"
append bss_conf "wmm_enabled=$wmm" "$N"
append bss_conf "wmm_enabled=1" "$N"
append bss_conf "ignore_broadcast_ssid=$hidden" "$N"
append bss_conf "uapsd_advertisement_enabled=$uapsd" "$N"
append bss_conf "utf8_ssid=$utf8_ssid" "$N"

View File

@ -778,7 +778,7 @@ function bss_check_mld(phydev, iface_name, bss)
bss.mld_bssid = mld_data.macaddr;
mld_data.iface[iface_name] = true;
if (!access('/sys/class/net/' + iface_name, 'x'))
if (!access('/sys/class/net/' + bss.ifname, 'x'))
mld_data.has_wdev = false;
if (mld_data.has_wdev)
@ -1166,20 +1166,22 @@ let main_obj = {
return 0;
}
if (!req.args.frequency)
return libubus.STATUS_INVALID_ARGUMENT;
let freq_info;
if (req.args.frequency) {
freq_info = iface_freq_info(iface, config, req.args);
if (!freq_info)
return libubus.STATUS_UNKNOWN_ERROR;
let freq_info = iface_freq_info(iface, config, req.args);
if (!freq_info)
return libubus.STATUS_UNKNOWN_ERROR;
let ret;
if (req.args.csa) {
freq_info.csa_count = req.args.csa_count ?? 10;
ret = iface.switch_channel(freq_info);
} else {
ret = iface.start(freq_info);
if (req.args.csa) {
freq_info.csa_count = req.args.csa_count ?? 10;
let ret = iface.switch_channel(freq_info);
if (!ret)
return libubus.STATUS_UNKNOWN_ERROR;
return 0;
}
}
let ret = iface.start(freq_info);
if (!ret)
return libubus.STATUS_UNKNOWN_ERROR;
@ -1208,6 +1210,34 @@ let main_obj = {
return ret;
}
},
switch_channel: {
args: {
phy: "",
radio: 0,
csa_count: 0,
sec_channel: 0,
oper_chwidth: 0,
frequency: 0,
center_freq1: 0,
center_freq2: 0,
},
call: function(req) {
let phy = phy_name(req.args.phy, req.args.radio);
if (!req.args.frequency || !phy)
return libubus.STATUS_INVALID_ARGUMENT;
let iface = hostapd.interfaces[phy];
if (!iface)
return libubus.STATUS_NOT_FOUND;
req.args.csa_count ??= 10;
let ret = iface.switch_channel(req.args);
if (!ret)
return libubus.STATUS_UNKNOWN_ERROR;
return 0;
},
},
mld_set: {
args: {
config: {}

View File

@ -303,6 +303,9 @@ function mld_update_phy(phy, ifaces) {
}
function mld_start() {
if (wpas.data.mld_pending)
return;
wpas.printf(`Start pending MLD interfaces\n`);
let phy_list = {};
@ -501,6 +504,7 @@ let main_obj = {
if (!req.args.config)
return libubus.STATUS_INVALID_ARGUMENT;
wpas.data.mld_pending = true;
mld_set_config(req.args.config);
return 0;
}
@ -508,6 +512,7 @@ let main_obj = {
mld_start: {
args: {},
call: function(req) {
wpas.data.mld_pending = false;
mld_start();
return 0;
}

View File

@ -582,10 +582,8 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
if (!iface)
return NULL;
if (!info) {
iface->freq = 0;
if (!info)
goto out;
}
if (ucv_type(info) != UC_OBJECT)
return NULL;

View File

@ -12,9 +12,9 @@ PKG_RELEASE:=4
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/odhcpd.git
PKG_MIRROR_HASH:=3bbc3be7bec0336ef50042f7722b580066c31b2d536d335dd2eecf4a1876d2ec
PKG_SOURCE_DATE:=2025-09-16
PKG_SOURCE_VERSION:=c9816de148cc3e8096e67519d2c081ffeb9b4857
PKG_MIRROR_HASH:=4745093b58a221252fd092a40f2902e2a45a8ec972bcaa8592602f20acf26aa2
PKG_SOURCE_DATE:=2025-09-27
PKG_SOURCE_VERSION:=bc9f9d93d4d6b8feb7b19235d7f0371480fc679d
PKG_MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
PKG_LICENSE:=GPL-2.0

View File

@ -1,431 +0,0 @@
From fa15869456e8c9f472f1470092f61d8854972028 Mon Sep 17 00:00:00 2001
From: Aviana Cruz <gwencroft@proton.me>
Date: Sat, 16 Sep 2023 15:04:12 +0000
Subject: [PATCH] odhcpd: improve RFC 9096 compliance
and allow configuring upper limit for preferred and valid lifetime.
Signed-off-by: Aviana Cruz <gwencroft@proton.me>
---
README | 12 +++++-----
src/config.c | 35 ++++++++++++++++++-----------
src/dhcpv6-ia.c | 49 ++++++++++++++++++++++++++--------------
src/odhcpd.h | 8 +++++--
src/router.c | 60 ++++++++++++++++++++++++++-----------------------
5 files changed, 98 insertions(+), 66 deletions(-)
--- a/README
+++ b/README
@@ -119,7 +119,9 @@ domain list <local search domain> Sear
leasetime string 12h DHCPv4 address leasetime
start integer 100 DHCPv4 pool start
limit integer 150 DHCPv4 pool size
-preferred_lifetime string 7d Value for the preferred lifetime
+max_preferred_lifetime string 45m Upper limit for the preferred lifetime
+ for a prefix
+max_valid_lifetime string 90m Upper limit for the valid lifetime
for a prefix
ra_default integer 0 Override default route
0: default, 1: ignore no public address, 2: ignore all
@@ -134,11 +136,9 @@ ra_maxinterval integer 600 Maximum ti
sending unsolicited RA
ra_mininterval integer 200 Minimum time allowed between
sending unsolicited RA
-ra_lifetime integer 1800 Value to be placed in Router
- Lifetime field of RA
-ra_useleasetime bool 0 Use configured leasetime as
- limit for the preferred and
- valid lifetime of a prefix
+ra_lifetime integer 2700 Value to be placed in Router
+ Lifetime field of RA. Not recommended to be
+ more than 2700 (RFC9096).
ra_reachabletime integer 0 Reachable Time in milliseconds to be
advertised in RA messages
ra_retranstime integer 0 Retransmit Time in milliseconds to be
--- a/src/config.c
+++ b/src/config.c
@@ -97,7 +97,6 @@ enum {
IFACE_ATTR_RA_MININTERVAL,
IFACE_ATTR_RA_MAXINTERVAL,
IFACE_ATTR_RA_LIFETIME,
- IFACE_ATTR_RA_USELEASETIME,
IFACE_ATTR_RA_REACHABLETIME,
IFACE_ATTR_RA_RETRANSTIME,
IFACE_ATTR_RA_HOPLIMIT,
@@ -109,7 +108,8 @@ enum {
IFACE_ATTR_NDPROXY_ROUTING,
IFACE_ATTR_NDPROXY_SLAVE,
IFACE_ATTR_PREFIX_FILTER,
- IFACE_ATTR_PREFERRED_LIFETIME,
+ IFACE_ATTR_MAX_PREFERRED_LIFETIME,
+ IFACE_ATTR_MAX_VALID_LIFETIME,
IFACE_ATTR_NTP,
IFACE_ATTR_MAX
};
@@ -153,7 +153,6 @@ static const struct blobmsg_policy iface
[IFACE_ATTR_RA_MININTERVAL] = { .name = "ra_mininterval", .type = BLOBMSG_TYPE_INT32 },
[IFACE_ATTR_RA_MAXINTERVAL] = { .name = "ra_maxinterval", .type = BLOBMSG_TYPE_INT32 },
[IFACE_ATTR_RA_LIFETIME] = { .name = "ra_lifetime", .type = BLOBMSG_TYPE_INT32 },
- [IFACE_ATTR_RA_USELEASETIME] = { .name = "ra_useleasetime", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_RA_REACHABLETIME] = { .name = "ra_reachabletime", .type = BLOBMSG_TYPE_INT32 },
[IFACE_ATTR_RA_RETRANSTIME] = { .name = "ra_retranstime", .type = BLOBMSG_TYPE_INT32 },
[IFACE_ATTR_RA_HOPLIMIT] = { .name = "ra_hoplimit", .type = BLOBMSG_TYPE_INT32 },
@@ -163,7 +162,8 @@ static const struct blobmsg_policy iface
[IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING },
- [IFACE_ATTR_PREFERRED_LIFETIME] = { .name = "preferred_lifetime", .type = BLOBMSG_TYPE_STRING },
+ [IFACE_ATTR_MAX_PREFERRED_LIFETIME] = { .name = "max_preferred_lifetime", .type = BLOBMSG_TYPE_STRING },
+ [IFACE_ATTR_MAX_VALID_LIFETIME] = { .name = "max_valid_lifetime", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_NTP] = { .name = "ntp", .type = BLOBMSG_TYPE_ARRAY },
};
@@ -260,7 +260,8 @@ static void set_interface_defaults(struc
iface->ndp = MODE_DISABLED;
iface->learn_routes = 1;
iface->dhcp_leasetime = 43200;
- iface->preferred_lifetime = 604800; /* rfc4861#section-6.2.1: AdvPreferredLifetime 7 days */
+ iface->max_preferred_lifetime = ND_PREFERRED_LIMIT;
+ iface->max_valid_lifetime = ND_VALID_LIMIT;
iface->dhcpv4_start.s_addr = htonl(START_DEFAULT);
iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1);
iface->dhcpv6_assignall = true;
@@ -998,15 +999,26 @@ int config_parse_interface(void *data, s
}
- if ((c = tb[IFACE_ATTR_PREFERRED_LIFETIME])) {
+ if ((c = tb[IFACE_ATTR_MAX_PREFERRED_LIFETIME])) {
double time = parse_leasetime(c);
- if (time >= 0)
- iface->preferred_lifetime = time;
- else
+ if (time >= 0) {
+ iface->max_preferred_lifetime = time;
+ } else {
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
- iface_attrs[IFACE_ATTR_PREFERRED_LIFETIME].name, iface->name);
+ iface_attrs[IFACE_ATTR_MAX_PREFERRED_LIFETIME].name, iface->name);
+ }
+ }
+ if ((c = tb[IFACE_ATTR_MAX_VALID_LIFETIME])) {
+ double time = parse_leasetime(c);
+
+ if (time >= 0) {
+ iface->max_valid_lifetime = time;
+ } else {
+ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
+ iface_attrs[IFACE_ATTR_MAX_VALID_LIFETIME].name, iface->name);
+ }
}
if ((c = tb[IFACE_ATTR_START])) {
@@ -1330,9 +1342,6 @@ int config_parse_interface(void *data, s
if ((c = tb[IFACE_ATTR_RA_LIFETIME]))
iface->ra_lifetime = blobmsg_get_u32(c);
- if ((c = tb[IFACE_ATTR_RA_USELEASETIME]))
- iface->ra_useleasetime = blobmsg_get_bool(c);
-
if ((c = tb[IFACE_ATTR_RA_DNS]))
iface->ra_dns = blobmsg_get_bool(c);
--- a/src/dhcpv6-ia.c
+++ b/src/dhcpv6-ia.c
@@ -120,7 +120,7 @@ static inline bool valid_prefix_length(c
static inline bool valid_addr(const struct odhcpd_ipaddr *addr, time_t now)
{
- return (addr->prefix <= 96 && addr->preferred_lt > (uint32_t)now);
+ return (addr->prefix <= 96 && addr->valid_lt > (uint32_t)now && addr->preferred_lt > (uint32_t)now);
}
static size_t get_preferred_addr(const struct odhcpd_ipaddr *addrs, const size_t addrlen)
@@ -1039,17 +1039,27 @@ static size_t build_ia(uint8_t *buf, siz
}
if (a) {
- uint32_t leasetime, preferred_lt;
+ uint32_t leasetime;
if (a->leasetime) {
leasetime = a->leasetime;
- preferred_lt = a->leasetime;
} else {
leasetime = iface->dhcp_leasetime;
- preferred_lt = iface->preferred_lifetime;
}
- uint32_t valid_lt = leasetime;
+ uint32_t floor_preferred_lifetime, floor_valid_lifetime; /* For calculating T1 / T2 */
+
+ if (iface->max_preferred_lifetime && iface->max_preferred_lifetime < leasetime) {
+ floor_preferred_lifetime = iface->max_preferred_lifetime;
+ } else {
+ floor_preferred_lifetime = leasetime;
+ }
+
+ if (iface->max_valid_lifetime && iface->max_valid_lifetime < leasetime) {
+ floor_valid_lifetime = iface->max_valid_lifetime;
+ } else {
+ floor_valid_lifetime = leasetime;
+ }
struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len;
@@ -1073,15 +1083,20 @@ static size_t build_ia(uint8_t *buf, siz
prefix_preferred_lt = addrs[i].preferred_lt;
prefix_valid_lt = addrs[i].valid_lt;
- if (prefix_preferred_lt != UINT32_MAX)
+ if (prefix_preferred_lt != UINT32_MAX) {
prefix_preferred_lt -= now;
- if (prefix_preferred_lt > preferred_lt)
- prefix_preferred_lt = preferred_lt;
+ if (iface->max_preferred_lifetime && prefix_preferred_lt > iface->max_preferred_lifetime)
+ prefix_preferred_lt = iface->max_preferred_lifetime;
+ }
- if (prefix_valid_lt != UINT32_MAX)
+ if (prefix_valid_lt != UINT32_MAX) {
prefix_valid_lt -= now;
+ if (iface->max_valid_lifetime && prefix_valid_lt > iface->max_valid_lifetime)
+ prefix_valid_lt = iface->max_valid_lifetime;
+ }
+
if (prefix_valid_lt > leasetime)
prefix_valid_lt = leasetime;
@@ -1135,24 +1150,24 @@ static size_t build_ia(uint8_t *buf, siz
/* Calculate T1 / T2 based on non-deprecated addresses */
if (prefix_preferred_lt > 0) {
- if (prefix_preferred_lt < preferred_lt)
- preferred_lt = prefix_preferred_lt;
+ if (floor_preferred_lifetime > prefix_preferred_lt)
+ floor_preferred_lifetime = prefix_preferred_lt;
- if (prefix_valid_lt < valid_lt)
- valid_lt = prefix_valid_lt;
+ if (floor_valid_lifetime > prefix_valid_lt)
+ floor_valid_lifetime = prefix_valid_lt;
}
}
if (!INFINITE_VALID(a->valid_until))
/* UINT32_MAX is RFC defined as infinite lease-time */
- a->valid_until = (valid_lt == UINT32_MAX) ? 0 : valid_lt + now;
+ a->valid_until = (floor_valid_lifetime == UINT32_MAX) ? 0 : floor_valid_lifetime + now;
if (!INFINITE_VALID(a->preferred_until))
/* UINT32_MAX is RFC defined as infinite lease-time */
- a->preferred_until = (preferred_lt == UINT32_MAX) ? 0 : preferred_lt + now;
+ a->preferred_until = (floor_preferred_lifetime == UINT32_MAX) ? 0 : floor_preferred_lifetime + now;
- o_ia.t1 = htonl((preferred_lt == UINT32_MAX) ? preferred_lt : preferred_lt * 5 / 10);
- o_ia.t2 = htonl((preferred_lt == UINT32_MAX) ? preferred_lt : preferred_lt * 8 / 10);
+ o_ia.t1 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 5 / 10);
+ o_ia.t2 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 8 / 10);
if (!o_ia.t1)
o_ia.t1 = htonl(1);
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -37,6 +37,10 @@
// RFC 8781 defines PREF64 option
#define ND_OPT_PREF64 38
+// RFC9096 defines recommended option lifetimes configuration values
+#define ND_PREFERRED_LIMIT 2700
+#define ND_VALID_LIMIT 5400
+
// RFC 9463 - Discovery of Network-designated Resolvers (DNR)
#define ND_OPT_DNR 144
@@ -328,7 +332,6 @@ struct interface {
bool ra_slaac;
bool ra_not_onlink;
bool ra_advrouter;
- bool ra_useleasetime;
bool ra_dns;
uint8_t pref64_length;
uint8_t pref64_plc;
@@ -346,7 +349,8 @@ struct interface {
uint32_t ra_retranstime;
uint32_t ra_hoplimit;
int ra_mtu;
- uint32_t preferred_lifetime;
+ uint32_t max_preferred_lifetime;
+ uint32_t max_valid_lifetime;
// DHCP
uint32_t dhcp_leasetime;
--- a/src/router.c
+++ b/src/router.c
@@ -342,13 +342,8 @@ static int calc_adv_interval(struct inte
*maxival = iface->ra_maxinterval;
- /*
- * rfc4861#section-6.2.1 : AdvDefaultLifetime Default: 3 * MaxRtrAdvInterval
- * therefore max interval shall be no greater than 1/3 of the lowest valid
- * lease time of all known prefixes.
- */
- if (*maxival > lowest_found_lifetime/3)
- *maxival = lowest_found_lifetime/3;
+ if (*maxival > lowest_found_lifetime)
+ *maxival = lowest_found_lifetime;
if (*maxival > MaxRtrAdvInterval)
*maxival = MaxRtrAdvInterval;
@@ -376,16 +371,17 @@ static int calc_adv_interval(struct inte
static uint32_t calc_ra_lifetime(struct interface *iface, uint32_t maxival)
{
- uint32_t lifetime = 3*maxival;
+ uint32_t lifetime = iface->max_preferred_lifetime;
if (iface->ra_lifetime >= 0) {
lifetime = iface->ra_lifetime;
- if (lifetime > 0 && lifetime < maxival)
- lifetime = maxival;
- else if (lifetime > 9000)
- lifetime = 9000;
}
+ if (lifetime > 0 && lifetime < maxival)
+ lifetime = maxival;
+ else if (lifetime > 9000)
+ lifetime = 9000;
+
return lifetime;
}
@@ -470,10 +466,10 @@ static int send_router_advert(struct int
size_t valid_addr_cnt = 0, invalid_addr_cnt = 0;
/*
* lowest_found_lifetime stores the lowest lifetime of all prefixes;
- * necessary to find shortest adv interval necessary
+ * necessary to find longest adv interval necessary
* for shortest lived prefix
*/
- uint32_t lowest_found_lifetime = UINT32_MAX, maxival, lifetime;
+ uint32_t lowest_found_lifetime = UINT32_MAX, highest_found_lifetime = 0, maxival, ra_lifetime;
int msecs, mtu = iface->ra_mtu, hlim = iface->ra_hoplimit;
bool default_route = false;
bool valid_prefix = false;
@@ -611,17 +607,16 @@ static int send_router_advert(struct int
if (addr->preferred_lt > (uint32_t)now) {
preferred_lt = TIME_LEFT(addr->preferred_lt, now);
- if (preferred_lt > iface->preferred_lifetime) {
- /* set to possibly user mandated preferred_lt */
- preferred_lt = iface->preferred_lifetime;
+ if (iface->max_preferred_lifetime && preferred_lt > iface->max_preferred_lifetime) {
+ preferred_lt = iface->max_preferred_lifetime;
}
}
if (addr->valid_lt > (uint32_t)now) {
valid_lt = TIME_LEFT(addr->valid_lt, now);
- if (iface->ra_useleasetime && valid_lt > iface->dhcp_leasetime)
- valid_lt = iface->dhcp_leasetime;
+ if (iface->max_valid_lifetime && valid_lt > iface->max_valid_lifetime)
+ valid_lt = iface->max_valid_lifetime;
}
if (preferred_lt > valid_lt) {
@@ -639,6 +634,11 @@ static int send_router_advert(struct int
if ((!IN6_IS_ADDR_ULA(&addr->addr.in6) || iface->default_router) && valid_lt)
valid_prefix = true;
+ if (!IN6_IS_ADDR_ULA(&addr->addr.in6) && valid_lt) {
+ if (highest_found_lifetime < valid_lt)
+ highest_found_lifetime = valid_lt;
+ }
+
odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr.in6,
(iface->ra_advrouter) ? 128 : addr->prefix);
p->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
@@ -660,7 +660,9 @@ static int send_router_advert(struct int
/* Calculate periodic transmit */
msecs = calc_adv_interval(iface, lowest_found_lifetime, &maxival);
- lifetime = calc_ra_lifetime(iface, maxival);
+ ra_lifetime = calc_ra_lifetime(iface, maxival);
+ if (!highest_found_lifetime)
+ highest_found_lifetime = ra_lifetime;
if (!iface->have_link_local) {
syslog(LOG_NOTICE, "Skip sending a RA on %s as no link local address is available", iface->name);
@@ -668,15 +670,15 @@ static int send_router_advert(struct int
}
if (default_route && valid_prefix) {
- adv.h.nd_ra_router_lifetime = htons(lifetime < UINT16_MAX ? lifetime : UINT16_MAX);
+ adv.h.nd_ra_router_lifetime = htons(ra_lifetime < UINT16_MAX ? ra_lifetime : UINT16_MAX);
} else {
adv.h.nd_ra_router_lifetime = 0;
if (default_route) {
syslog(LOG_WARNING, "A default route is present but there is no public prefix "
- "on %s thus we announce no default route by overriding ra_lifetime to 0!", iface->name);
+ "on %s thus we announce no default route by setting ra_lifetime to 0!", iface->name);
} else {
- syslog(LOG_WARNING, "No default route present, overriding ra_lifetime to 0!");
+ syslog(LOG_WARNING, "No default route present, setting ra_lifetime to 0!");
}
}
@@ -705,7 +707,7 @@ static int send_router_advert(struct int
memset(dns, 0, dns_sz);
dns->type = ND_OPT_RECURSIVE_DNS;
dns->len = 1 + (2 * dns_cnt);
- dns->lifetime = htonl(lifetime);
+ dns->lifetime = htonl(highest_found_lifetime);
memcpy(dns->addr, dns_addr, sizeof(struct in6_addr)*dns_cnt);
}
@@ -728,7 +730,7 @@ static int send_router_advert(struct int
memset(search, 0, search_sz);
search->type = ND_OPT_DNS_SEARCH;
search->len = search_len ? ((sizeof(*search) + search_padded) / 8) : 0;
- search->lifetime = htonl(lifetime);
+ search->lifetime = htonl(highest_found_lifetime);
memcpy(search->name, search_domain, search_len);
memset(&search->name[search_len], 0, search_padded - search_len);
}
@@ -741,7 +743,7 @@ static int send_router_advert(struct int
if (iface->pref64_length) {
/* RFC 8781 § 4.1 rounding up lifetime to multiple of 8 */
- uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : UINT16_MAX;
+ uint16_t pref64_lifetime = ra_lifetime < (UINT16_MAX - 7) ? ra_lifetime + 7 : (UINT16_MAX - 7);
pref64_sz = sizeof(*pref64);
pref64 = alloca(pref64_sz);
@@ -783,7 +785,7 @@ static int send_router_advert(struct int
if (iface->dnr[i].lifetime_set)
dnr->lifetime = htonl(iface->dnr[i].lifetime);
else
- dnr->lifetime = htonl(lifetime);
+ dnr->lifetime = htonl(highest_found_lifetime);
dnr->adn_len = htons(iface->dnr[i].adn_len);
memcpy(tmp, iface->dnr[i].adn, iface->dnr[i].adn_len);
@@ -858,7 +860,9 @@ static int send_router_advert(struct int
routes[routes_cnt].flags |= ND_RA_PREF_HIGH;
valid_lt = TIME_LEFT(addr->valid_lt, now);
- routes[routes_cnt].lifetime = htonl(valid_lt < lifetime ? valid_lt : lifetime);
+ if (iface->max_valid_lifetime && valid_lt > iface->max_valid_lifetime)
+ valid_lt = iface->max_valid_lifetime;
+ routes[routes_cnt].lifetime = htonl(valid_lt);
routes[routes_cnt].addr[0] = addr->addr.in6.s6_addr32[0];
routes[routes_cnt].addr[1] = addr->addr.in6.s6_addr32[1];
routes[routes_cnt].addr[2] = 0;

View File

@ -63,7 +63,7 @@ define Package/iwinfo
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Generalized Wireless Information utility
DEPENDS:=+libiwinfo @!WIFI_SCRIPTS_UCODE
DEPENDS:=+@!WIFI_SCRIPTS_UCODE:libiwinfo
endef
define Package/iwinfo/description
@ -111,10 +111,16 @@ define Package/libiwinfo-data/install
$(INSTALL_DATA) $(PKG_BUILD_DIR)/devices.txt $(1)/usr/share/libiwinfo/devices.txt
endef
define Package/iwinfo/install
ifdef CONFIG_WIFI_SCRIPTS_UCODE
define Package/iwinfo/install
:
endef
else
define Package/iwinfo/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwinfo $(1)/usr/bin/iwinfo
endef
endef
endif
$(eval $(call BuildPackage,libiwinfo))
$(eval $(call BuildPackage,libiwinfo-lua))

View File

@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=https://github.com/jow-/ucode.git
PKG_SOURCE_DATE:=2025-08-26
PKG_SOURCE_VERSION:=5f712ffd3f31f13ed4812cfb37c21dbef7a75e2b
PKG_MIRROR_HASH:=6093ceb320854f4d38180f163fd702bceb8785ed6574aa145021eda82a9cf7b4
PKG_SOURCE_DATE:=2025-09-29
PKG_SOURCE_VERSION:=1090abb125490d2f541f68453cc251daf94f8b04
PKG_MIRROR_HASH:=b68d893867add47b92d519a631c4e3bacec52eafae088b6a64ba3935f169bb15
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
PKG_LICENSE:=ISC

View File

@ -1,69 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 26 Aug 2025 10:17:22 +0200
Subject: [PATCH] ubus: add connection functions to global scope
Allows reusing a common global connection across modules
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/lib/ubus.c
+++ b/lib/ubus.c
@@ -511,16 +511,42 @@ uc_ubus_objects_cb(struct ubus_context *
static bool
_conn_get(uc_vm_t *vm, uc_ubus_connection_t **conn)
{
- uc_ubus_connection_t *c = uc_fn_thisval("ubus.connection");
+ uc_ubus_connection_t *c;
+ uc_value_t *res;
- if (!c)
- c = uc_fn_thisval("ubus.channel");
- if (!c)
- err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid connection context");
+ if (ucv_type(_uc_fn_this_res(vm)) == UC_OBJECT) {
+ res = uc_vm_registry_get(vm, "ubus.connection");
+ c = ucv_resource_data(res, "ubus.connection");
+
+ if (c && c->ctx.sock.fd >= 0)
+ goto out;
+
+ c = uc_ubus_conn_alloc(vm, NULL, "ubus.connection");
+ if (!c)
+ return NULL;
+
+ if (ubus_connect_ctx(&c->ctx, NULL)) {
+ ucv_put(c->res);
+ err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to connect to ubus socket");
+ }
+
+ ubus_add_uloop(&c->ctx);
- if (c->ctx.sock.fd < 0)
- err_return(UBUS_STATUS_CONNECTION_FAILED, "Connection is closed");
+ uc_vm_registry_set(vm, "ubus.connection", ucv_get(c->res));
+ }
+ else {
+ c = uc_fn_thisval("ubus.connection");
+ if (!c)
+ c = uc_fn_thisval("ubus.channel");
+
+ if (!c)
+ err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid connection context");
+ if (c->ctx.sock.fd < 0)
+ err_return(UBUS_STATUS_CONNECTION_FAILED, "Connection is closed");
+ }
+
+out:
*conn = c;
ok_return(true);
@@ -2606,6 +2632,7 @@ static void free_request(void *ud) {
void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
{
uc_function_list_register(scope, global_fns);
+ uc_function_list_register(scope, conn_fns);
#define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(UBUS_##x))
ADD_CONST(STATUS_OK);

View File

@ -43,12 +43,3 @@ for i in ${patchdir}/${patchpattern} ; do
exit 1
fi
done
# Check for rejects...
if [ "`find $targetdir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ] ; then
echo "Aborting. Reject files found."
exit 1
fi
# Remove backup files
find $targetdir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \;

View File

@ -16,10 +16,12 @@ 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
@ -32,13 +34,10 @@ 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_V2M=y
CONFIG_ARM_GIC_V3=y
@ -47,11 +46,10 @@ 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_MQ_PCI=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
@ -61,7 +59,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
@ -78,16 +75,20 @@ 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_CRC_CCITT=y
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_DEV_EIP93=y
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_DRBG_HMAC=y
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_GENIV=y
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_JITTERENTROPY=y
@ -103,21 +104,24 @@ CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_RNG_DEFAULT=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA3=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_ZSTD=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_INFO=y
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
@ -127,7 +131,6 @@ CONFIG_FS_MBCACHE=y
CONFIG_FUNCTION_ALIGNMENT=4
CONFIG_FUNCTION_ALIGNMENT_4B=y
CONFIG_FWNODE_MDIO=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
@ -145,6 +148,7 @@ CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IOREMAP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
@ -175,8 +179,6 @@ CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
CONFIG_HOTPLUG_CPU=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_AIROHA=y
# CONFIG_HISILICON_ERRATUM_162100801 is not set
# CONFIG_IDPF is not set
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
@ -184,8 +186,8 @@ CONFIG_INET_ESP=y
CONFIG_INET_IPCOMP=y
CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_TUNNEL=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IO_URING=y
CONFIG_IPC_NS=y
CONFIG_IPV6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
# CONFIG_IPV6_SUBTREES is not set
@ -211,12 +213,11 @@ CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LRU_GEN_WALKS_MMU=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
# CONFIG_MDIO_AIROHA is not set
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
# CONFIG_MDIO_AIROHA is not set
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
@ -237,23 +238,27 @@ CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MTK_NET_PHYLIB=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NET_AIROHA=y
CONFIG_NET_AIROHA_FLOW_STATS=y
CONFIG_NET_AIROHA_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
@ -271,6 +276,7 @@ CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OF_MDIO=y
CONFIG_PADATA=y
CONFIG_PAGE_POOL=y
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
@ -289,6 +295,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=y
# CONFIG_PCS_AIROHA_AN7583 is not set
CONFIG_PERF_EVENTS=y
@ -316,6 +323,8 @@ CONFIG_PINCTRL_AIROHA=y
# CONFIG_PINCTRL_MT8516 is not set
CONFIG_PM=y
CONFIG_PM_CLK=y
CONFIG_PM_GENERIC_DOMAINS=y
CONFIG_PM_GENERIC_DOMAINS_OF=y
CONFIG_PM_OPP=y
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_POWER_RESET=y
@ -362,11 +371,12 @@ CONFIG_SPI=y
CONFIG_SPI_AIROHA_SNFI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPLIT_PMD_PTLOCKS=y
CONFIG_SPLIT_PTE_PTLOCKS=y
CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=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
@ -376,6 +386,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TOOLS_SUPPORT_RELR=y
CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
@ -384,6 +395,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

View File

@ -490,8 +490,8 @@
reg = <0x0 0x1fbe3400 0x0 0xff>;
};
scuclk: clock-controller@1fa20000 {
compatible = "airoha,en7581-scu";
scuclk: clock-controller@1fb00000 {
compatible = "airoha,en7581-scu", "syscon";
reg = <0x0 0x1fb00000 0x0 0x970>;
#clock-cells = <1>;
#reset-cells = <1>;

View File

@ -10,7 +10,8 @@ define Device/Default
KERNEL_INITRAMFS = kernel-bin | lzma | \
fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd
FILESYSTEMS := squashfs
DEVICE_DTS_DIR := $(DTS_DIR)
DEVICE_DTS = $$(SOC)-$(lastword $(subst _, ,$(1)))
DEVICE_DTS_DIR := ../dts
IMAGES := sysupgrade.bin
IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | \
pad-rootfs | append-metadata

View File

@ -10,7 +10,6 @@ define Device/airoha_an7581-evb
DEVICE_MODEL := AN7581 Evaluation Board (SNAND)
DEVICE_PACKAGES := kmod-leds-pwm kmod-i2c-an7581 kmod-pwm-airoha kmod-input-gpio-keys-polled
DEVICE_DTS := an7581-evb
DEVICE_DTS_DIR := ../dts
DEVICE_DTS_CONFIG := config@1
KERNEL_LOADADDR := 0x80088000
IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | pad-rootfs | append-metadata
@ -21,7 +20,6 @@ define Device/airoha_an7581-evb-emmc
DEVICE_VENDOR := Airoha
DEVICE_MODEL := AN7581 Evaluation Board (EMMC)
DEVICE_DTS := an7581-evb-emmc
DEVICE_DTS_DIR := ../dts
DEVICE_PACKAGES := kmod-i2c-an7581
endef
TARGET_DEVICES += airoha_an7581-evb-emmc

View File

@ -30,7 +30,6 @@ define Device/airoha_an7583-evb
DEVICE_MODEL := AN7583 Evaluation Board (SNAND)
DEVICE_PACKAGES := kmod-leds-pwm kmod-input-gpio-keys-polled
DEVICE_DTS := an7583-evb
DEVICE_DTS_DIR := ../dts
DEVICE_DTS_CONFIG := config@1
KERNEL_LOADADDR := 0x80088000
IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | pad-rootfs | append-metadata
@ -45,7 +44,6 @@ define Device/airoha_an7583-evb-emmc
DEVICE_VENDOR := Airoha
DEVICE_MODEL := AN7583 Evaluation Board (EMMC)
DEVICE_DTS := an7583-evb-emmc
DEVICE_DTS_DIR := ../dts
DEVICE_PACKAGES := kmod-i2c-an7581
ARTIFACT/preloader.bin := an7583-preloader rfb
ARTIFACT/bl31-uboot.fip := an7583-bl31-uboot rfb

View File

@ -8,6 +8,5 @@ define Device/airoha_en7523-evb
DEVICE_VENDOR := Airoha
DEVICE_MODEL := EN7523 Evaluation Board
DEVICE_DTS := en7523-evb
DEVICE_DTS_DIR := ../dts
endef
TARGET_DEVICES += airoha_en7523-evb
TARGET_DEVICES += airoha_en7523-evb

View File

@ -1,95 +0,0 @@
From 6a325aed130bb68790e765f923e76ec5669d2da7 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Thu, 10 Apr 2025 12:04:04 +0200
Subject: [PATCH 2/2] net: phy: mediatek: add Airoha PHY ID to SoC driver
Airoha AN7581 SoC ship with a Switch based on the MT753x Switch embedded
in other SoC like the MT7581 and the MT7988. Similar to these they
require configuring some pin to enable LED PHYs.
Add support for the PHY ID for the Airoha embedded Switch and define a
simple probe function to toggle these pins. Also fill the LED functions
and add dedicated function to define LED polarity.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Link: https://patch.msgid.link/20250410100410.348-2-ansuelsmth@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 62 +++++++++++++++++++++++++++
2 files changed, 65 insertions(+), 1 deletion(-)
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -1454,6 +1454,53 @@ static int an7581_phy_led_polarity_set(s
MTK_PHY_LED_ON_POLARITY, val);
}
+static int an7581_phy_probe(struct phy_device *phydev)
+{
+ struct mtk_socphy_priv *priv;
+ struct pinctrl *pinctrl;
+
+ /* Toggle pinctrl to enable PHY LED */
+ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
+ if (IS_ERR(pinctrl))
+ dev_err(&phydev->mdio.bus->dev,
+ "Failed to setup PHY LED pinctrl\n");
+
+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
+static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,
+ unsigned long modes)
+{
+ u32 mode;
+ u16 val;
+
+ if (index >= MTK_PHY_MAX_LEDS)
+ return -EINVAL;
+
+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
+ switch (mode) {
+ case PHY_LED_ACTIVE_LOW:
+ val = MTK_PHY_LED_ON_POLARITY;
+ break;
+ case PHY_LED_ACTIVE_HIGH:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+ MTK_PHY_LED_ON_POLARITY, val);
+}
+
static struct phy_driver mtk_socphy_driver[] = {
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
@@ -1491,6 +1538,17 @@ static struct phy_driver mtk_socphy_driv
},
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581),
+ .name = "Airoha AN7581 PHY",
+ .probe = an7581_phy_probe,
+ .led_blink_set = mt798x_phy_led_blink_set,
+ .led_brightness_set = mt798x_phy_led_brightness_set,
+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
+ .led_polarity_set = an7581_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581),
.name = "Airoha AN7581 PHY",
.probe = an7581_phy_probe,
.led_blink_set = mt798x_phy_led_blink_set,

View File

@ -32,9 +32,10 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
{ \
.desc = { \
.func = { \
.name = #id, \
- .name = #id, \
- .groups = id##_groups, \
- .ngroups = ARRAY_SIZE(id##_groups), \
+ .name = id, \
+ .groups = table##_groups, \
+ .ngroups = ARRAY_SIZE(table##_groups), \
} \

View File

@ -11,6 +11,7 @@
model = "TRENDNET TEW-673GRU";
aliases {
label-mac-device = &eth1;
led-boot = &led_wps;
led-failsafe = &led_wps;
led-running = &led_wps;
@ -97,13 +98,15 @@
wifi@11,0 {
compatible = "pci168c,0029";
reg = <0x8800 0 0 0 0>;
qca,no-eeprom;
nvmem-cells = <&cal_caldata_1000>, <&macaddr_lan 0>;
nvmem-cell-names = "calibration", "mac-address";
};
wifi@12,0 {
compatible = "pci168c,0029";
reg = <0x9000 0 0 0 0>;
qca,no-eeprom;
nvmem-cells = <&cal_caldata_5000>, <&macaddr_wan 1>;
nvmem-cell-names = "calibration", "mac-address";
};
};
@ -141,6 +144,32 @@
label = "caldata";
reg = <0x660000 0x010000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
cal_caldata_1000: calibration@1000 {
reg = <0x1000 0xeb8>;
};
cal_caldata_5000: calibration@5000 {
reg = <0x5000 0xeb8>;
};
macaddr_lan: macaddr@ffa0 {
compatible = "mac-base";
reg = <0xffa0 0x11>;
#nvmem-cell-cells = <1>;
};
macaddr_wan: macaddr@ffb4 {
compatible = "mac-base";
reg = <0xffb4 0x11>;
#nvmem-cell-cells = <1>;
};
};
};
fwconcat1: partition@670000 {
@ -156,6 +185,9 @@
pll-data = <0x11110000 0x00001099 0x00991099>;
nvmem-cells = <&macaddr_lan 0>;
nvmem-cell-names = "mac-address";
fixed-link {
speed = <1000>;
full-duplex;
@ -167,5 +199,8 @@
pll-data = <0x11110000 0x00001099 0x00991099>;
nvmem-cells = <&macaddr_wan 0>;
nvmem-cell-names = "mac-address";
phy-handle = <&phy4>;
};

View File

@ -73,6 +73,9 @@
&eth0 {
status = "okay";
nvmem-cells = <&macaddr_mac_4 0>;
nvmem-cell-names = "mac-address";
gmac-config {
device = <&gmac>;
switch-phy-addr-swap = <0>;
@ -108,12 +111,34 @@
label = "art";
reg = <0x10000 0x10000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
cal_art_1000: calibration@1000 {
reg = <0x1000 0x440>;
};
};
};
mac: partition@20000 {
partition@20000 {
label = "mac";
reg = <0x20000 0x10000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_mac_4: macaddr@4 {
compatible = "mac-base";
reg = <0x4 0x11>;
#nvmem-cell-cells = <1>;
};
};
};
partition@30000 {
@ -139,5 +164,7 @@
&wmac {
status = "okay";
qca,no-eeprom;
nvmem-cells = <&cal_art_1000>, <&macaddr_mac_4 0>;
nvmem-cell-names = "calibration", "mac-address";
};

View File

@ -36,4 +36,11 @@
&pcie {
status = "okay";
wifi@0,0 {
compatible = "qcom,ath10k";
reg = <0x0000 0 0 0 0>;
nvmem-cells = <&macaddr_mib0_66 0>;
nvmem-cell-names = "mac-address";
};
};

View File

@ -36,4 +36,11 @@
&pcie {
status = "okay";
wifi@0,0 {
compatible = "pci168c,0030";
reg = <0x0000 0 0 0 0>;
nvmem-cells = <&macaddr_mib0_66 0>;
nvmem-cell-names = "mac-address";
};
};

View File

@ -58,13 +58,8 @@
ath9k: wifi@0,0 {
compatible = "pci168c,0030";
reg = <0x0000 0 0 0 0>;
/* "mac-address" currently does not work for
ath9k pci devices. these below are retained for future
improvements. */
/* nvmem-cells = <&macaddr_wan 1>, <&cal_art_5000>;
nvmem-cell-names = "mac-address", "calibration";
*/
qca,no-eeprom; /* remove this when "mac-address" works */
nvmem-cells = <&macaddr_wan 1>, <&cal_art_5000>;
nvmem-cell-names = "mac-address", "calibration";
};
};
@ -109,7 +104,7 @@
read-only;
};
mac: partition@fe0000 {
partition@fe0000 {
label = "mac";
reg = <0xfe0000 0x010000>;
read-only;

View File

@ -62,6 +62,20 @@
label = "art";
reg = <0xff0000 0x010000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
cal_art_1000: calibration@1000 {
reg = <0x1000 0x440>;
};
cal_art_5000: calibration@5000 {
reg = <0x5000 0x440>;
};
};
};
};
};
@ -77,12 +91,14 @@
wifi@0,0 {
compatible = "pci168c,0033";
reg = <0x0000 0 0 0 0>;
qca,no-eeprom;
nvmem-cells = <&cal_art_5000>;
nvmem-cell-names = "calibration";
};
};
&wmac {
status = "okay";
qca,no-eeprom;
nvmem-cells = <&cal_art_1000>;
nvmem-cell-names = "calibration";
};

View File

@ -11,6 +11,7 @@
model = "D-Link DCH-G020 A1";
aliases {
label-mac-device = &eth0;
led-boot = &led_power;
led-failsafe = &led_power;
led-running = &led_power;
@ -129,6 +130,24 @@
label = "mp";
reg = <0x20000 0x10000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_mp_1: macaddr@1 {
compatible = "mac-base";
reg = <0x1 0x11>;
#nvmem-cell-cells = <1>;
};
macaddr_mp_13: macaddr@13 {
compatible = "mac-base";
reg = <0x13 0x11>;
#nvmem-cell-cells = <1>;
};
};
};
partition@30000 {
@ -168,11 +187,14 @@
&eth0 {
status = "okay";
nvmem-cells = <&macaddr_mp_1 0>;
nvmem-cell-names = "mac-address";
};
&wmac {
status = "okay";
nvmem-cells = <&cal_art_1000>;
nvmem-cell-names = "calibration";
nvmem-cells = <&cal_art_1000>, <&macaddr_mp_13 0>;
nvmem-cell-names = "calibration", "mac-address";
};

View File

@ -8,6 +8,7 @@
/ {
aliases {
label-mac-device = &eth0;
led-boot = &led_power;
led-failsafe = &led_status;
led-running = &led_power;
@ -106,6 +107,24 @@
label = "mp";
reg = <0x20000 0x10000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_mp_1: macaddr@1 {
compatible = "mac-base";
reg = <0x1 0x11>;
#nvmem-cell-cells = <1>;
};
macaddr_mp_13: macaddr@13 {
compatible = "mac-base";
reg = <0x13 0x11>;
#nvmem-cell-cells = <1>;
};
};
};
partition@30000 {
@ -125,11 +144,14 @@
&eth0 {
status = "okay";
nvmem-cells = <&macaddr_mp_1 0>;
nvmem-cell-names = "mac-address";
};
&wmac {
status = "okay";
nvmem-cells = <&cal_art_1000>;
nvmem-cell-names = "calibration";
nvmem-cells = <&cal_art_1000>, <&macaddr_mp_13 0>;
nvmem-cell-names = "calibration", "mac-address";
};

View File

@ -690,12 +690,6 @@ ath79_setup_macs()
plc_mac=$(mtd_get_mac_ascii art "protest_plc_mac")
[ -n "$plc_mac" ] && ucidef_set_interface_macaddr "plc" $plc_mac
;;
dlink,dap-1330-a1|\
dlink,dap-1365-a1|\
dlink,dch-g020-a1)
lan_mac=$(mtd_get_mac_text "mp" 0x1)
label_mac=$lan_mac
;;
dlink,dap-2230-a1|\
dlink,dap-2660-a1|\
dlink,dap-2680-a1|\
@ -710,14 +704,6 @@ ath79_setup_macs()
dlink,dir-629-a1)
wan_mac=$(mtd_get_mac_text "mfcdata" 0x6a)
;;
trendnet,tew-673gru)
lan_mac=$(mtd_get_mac_text "caldata" 0xffa0)
wan_mac=$(mtd_get_mac_text "caldata" 0xffb4)
label_mac=$wan_mac
;;
dlink,dir-505)
lan_mac=$(mtd_get_mac_text "mac" 0x4)
;;
dlink,dir-825-c1|\
dlink,dir-835-a1)
wan_mac=$(mtd_get_mac_text "mac" 0x18)

View File

@ -20,15 +20,6 @@ case "$FIRMWARE" in
avm,fritzdvbc)
caldata_extract_reverse "urlader" 0x1541 0x440
;;
dlink,dir-505)
caldata_extract "art" 0x1000 0x440
ath9k_patch_mac $(mtd_get_mac_text "mac" 0x4)
;;
wd,mynet-n600|\
wd,mynet-n750)
caldata_extract "art" 0x1000 0x440
ath9k_patch_mac $(mtd_get_mac_ascii devdata "wlan24mac")
;;
engenius,ecb1200|\
engenius,ecb1750)
caldata_extract "art" 0x1000 0x440
@ -64,11 +55,6 @@ case "$FIRMWARE" in
buffalo,wzr-hp-g450h)
caldata_extract "art" 0x1000 0x440
;;
dlink,dir-825-c1|\
dlink,dir-835-a1)
caldata_extract "art" 0x5000 0x440
ath9k_patch_mac $(macaddr_add $(mtd_get_mac_text "mac" 0x18) 1)
;;
enterasys,ws-ap3705i)
caldata_extract "calibrate" 0x5000 0x440
ath9k_patch_mac $(mtd_get_mac_ascii u-boot-env0 RADIOADDR0)
@ -80,11 +66,6 @@ case "$FIRMWARE" in
ubnt,rocket-m)
caldata_extract "art" 0x1000 0x1000
;;
wd,mynet-n600|\
wd,mynet-n750)
caldata_extract "art" 0x5000 0x440
ath9k_patch_mac $(mtd_get_mac_ascii devdata "wlan5mac")
;;
wd,mynet-wifi-rangeextender)
caldata_extract "art" 0x1000 0x440
ath9k_patch_mac $(nvram get wl0_hwaddr)
@ -100,10 +81,6 @@ case "$FIRMWARE" in
buffalo,wzr-hp-ag300h)
caldata_extract "art" 0x1000 0xeb8
;;
trendnet,tew-673gru)
caldata_extract "caldata" 0x1000 0xeb8
ath9k_patch_mac_crc $(mtd_get_mac_text "caldata" 0xffa0) 0x20c
;;
meraki,mr16)
caldata_extract "art" 0x11000 0xeb8
;;
@ -118,10 +95,6 @@ case "$FIRMWARE" in
buffalo,wzr-hp-ag300h)
caldata_extract "art" 0x5000 0xeb8
;;
trendnet,tew-673gru)
caldata_extract "caldata" 0x5000 0xeb8
ath9k_patch_mac_crc $(macaddr_add $(mtd_get_mac_text "caldata" 0xffb4) 1) 0x20c
;;
meraki,mr16)
caldata_extract "art" 0x15000 0xeb8
;;

View File

@ -24,11 +24,6 @@ case "$board" in
[ "$PHYNBR" -eq 1 ] && \
mtd_get_mac_ascii art "protest_ath0_mac" > /sys${DEVPATH}/macaddress
;;
dlink,dap-1330-a1|\
dlink,dap-1365-a1|\
dlink,dch-g020-a1)
mtd_get_mac_text "mp" 0x13 > /sys${DEVPATH}/macaddress
;;
dlink,dap-2230-a1|\
dlink,dap-3320-a1)
mtd_get_mac_ascii bdcfg "wlanmac" > /sys${DEVPATH}/macaddress
@ -120,12 +115,11 @@ case "$board" in
[ "$PHYNBR" -eq 1 ] && \
macaddr_add $base_mac 1 > /sys${DEVPATH}/macaddress
;;
zyxel,nwa1123-ac)
wd,mynet-n600|\
wd,mynet-n750)
[ "$PHYNBR" -eq 0 ] && \
mtd_get_mac_text mib0 0x66 > /sys${DEVPATH}/macaddress
;;
zyxel,nwa1123-ni)
mtd_get_mac_ascii devdata wlan24mac > /sys${DEVPATH}/macaddress
[ "$PHYNBR" -eq 1 ] && \
mtd_get_mac_text mib0 0x66 > /sys${DEVPATH}/macaddress
mtd_get_mac_ascii devdata wlan5mac > /sys${DEVPATH}/macaddress
;;
esac

View File

@ -13,6 +13,10 @@ define Device/mikrotik_nor
IMAGE/sysupgrade.bin := append-kernel | yaffs-filesystem -M | \
pad-to $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | \
check-size | append-metadata
IMAGES += sysupgrade-v7.bin
IMAGE/sysupgrade-v7.bin := append-kernel | kernel-pack-npk | \
yaffs-filesystem -M | pad-to $$$$(BLOCKSIZE) | \
append-rootfs | pad-rootfs | check-size | append-metadata
endef
define Device/mikrotik_nand

View File

@ -3,7 +3,48 @@
PART_NAME=firmware
REQUIRE_IMAGE_METADATA=1
platform_check_image_mikrotik_nor() {
local bootfwver bootfwmajor
local bootentry="$(dd bs=10 skip=1 count=1 if="$1" 2>/dev/null | xargs -0)"
read -r bootfwver < /sys/firmware/mikrotik/hard_config/booter_version
bootfwmajor="${bootfwver%%.*}"
if [ "$((bootfwmajor))" = 0 ]; then
v "invalid RouterBOOT version"
return 1
elif [ "$bootfwmajor" -le 6 ] && [ "$bootentry" != "kernel" ]; then
v "RouterBOOT 6 and earlier requires ELF-in-YAFFS image"
return 1
elif [ "$bootfwmajor" -ge 7 ] && [ "$bootentry" != "bootimage" ]; then
v "RouterBOOT 7 and later requires NPK-in-YAFFS image"
return 1
fi
return 0
}
platform_check_image() {
case "$board" in
mikrotik,routerboard-2011uias-2hnd|\
mikrotik,routerboard-493g|\
mikrotik,routerboard-911g-5hpacd|\
mikrotik,routerboard-911g-xhpnd|\
mikrotik,routerboard-912uag-2hpnd|\
mikrotik,routerboard-921gs-5hpacd-15s|\
mikrotik,routerboard-922uags-5hpacd|\
mikrotik,routerboard-951g-2hnd|\
mikrotik,routerboard-951ui-2hnd|\
mikrotik,routerboard-sxt-5nd-r2)
return 0
;;
*)
platform_check_image_mikrotik_nor "$1"
return $?
;;
esac
return 0
}

View File

@ -0,0 +1,329 @@
From 6b88293aae7fb78872e5cc1ec36e2f750ae12e38 Mon Sep 17 00:00:00 2001
From: Markus Stockhausen <markus.stockhausen@gmx.de>
Date: Wed, 10 Sep 2025 14:32:58 -0400
Subject: mtd: nand: move nand_check_erased_ecc_chunk() to nand/core
The check function for bitflips in erased blocks will be needed
by the Realtek ECC engine driver (which is currently under
development). Right now it is located in raw/nand_base.c.
While this is sufficient for the current usecases, there is
no real dependency for an ECC engine on the raw nand library.
Move the function over to a more generic place in core library.
Suggested-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/core.c | 131 +++++++++++++++++++++++++++++++++++++++
drivers/mtd/nand/raw/nand_base.c | 131 ---------------------------------------
include/linux/mtd/nand.h | 5 ++
include/linux/mtd/rawnand.h | 5 --
4 files changed, 136 insertions(+), 136 deletions(-)
--- a/drivers/mtd/nand/core.c
+++ b/drivers/mtd/nand/core.c
@@ -13,6 +13,137 @@
#include <linux/mtd/nand.h>
/**
+ * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
+ * @buf: buffer to test
+ * @len: buffer length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a buffer contains only 0xff, which means the underlying region
+ * has been erased and is ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region is not erased.
+ * Note: The logic of this function has been extracted from the memweight
+ * implementation, except that nand_check_erased_buf function exit before
+ * testing the whole buffer if the number of bitflips exceed the
+ * bitflips_threshold value.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold.
+ */
+static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
+{
+ const unsigned char *bitmap = buf;
+ int bitflips = 0;
+ int weight;
+
+ for (; len && ((uintptr_t)bitmap) % sizeof(long);
+ len--, bitmap++) {
+ weight = hweight8(*bitmap);
+ bitflips += BITS_PER_BYTE - weight;
+ if (unlikely(bitflips > bitflips_threshold))
+ return -EBADMSG;
+ }
+
+ for (; len >= sizeof(long);
+ len -= sizeof(long), bitmap += sizeof(long)) {
+ unsigned long d = *((unsigned long *)bitmap);
+ if (d == ~0UL)
+ continue;
+ weight = hweight_long(d);
+ bitflips += BITS_PER_LONG - weight;
+ if (unlikely(bitflips > bitflips_threshold))
+ return -EBADMSG;
+ }
+
+ for (; len > 0; len--, bitmap++) {
+ weight = hweight8(*bitmap);
+ bitflips += BITS_PER_BYTE - weight;
+ if (unlikely(bitflips > bitflips_threshold))
+ return -EBADMSG;
+ }
+
+ return bitflips;
+}
+
+/**
+ * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
+ * 0xff data
+ * @data: data buffer to test
+ * @datalen: data length
+ * @ecc: ECC buffer
+ * @ecclen: ECC length
+ * @extraoob: extra OOB buffer
+ * @extraooblen: extra OOB length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a data buffer and its associated ECC and OOB data contains only
+ * 0xff pattern, which means the underlying region has been erased and is
+ * ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region as not erased.
+ *
+ * Note:
+ * 1/ ECC algorithms are working on pre-defined block sizes which are usually
+ * different from the NAND page size. When fixing bitflips, ECC engines will
+ * report the number of errors per chunk, and the NAND core infrastructure
+ * expect you to return the maximum number of bitflips for the whole page.
+ * This is why you should always use this function on a single chunk and
+ * not on the whole page. After checking each chunk you should update your
+ * max_bitflips value accordingly.
+ * 2/ When checking for bitflips in erased pages you should not only check
+ * the payload data but also their associated ECC data, because a user might
+ * have programmed almost all bits to 1 but a few. In this case, we
+ * shouldn't consider the chunk as erased, and checking ECC bytes prevent
+ * this case.
+ * 3/ The extraoob argument is optional, and should be used if some of your OOB
+ * data are protected by the ECC engine.
+ * It could also be used if you support subpages and want to attach some
+ * extra OOB data to an ECC chunk.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold. In case of success, the passed buffers are filled with 0xff.
+ */
+int nand_check_erased_ecc_chunk(void *data, int datalen,
+ void *ecc, int ecclen,
+ void *extraoob, int extraooblen,
+ int bitflips_threshold)
+{
+ int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
+
+ data_bitflips = nand_check_erased_buf(data, datalen,
+ bitflips_threshold);
+ if (data_bitflips < 0)
+ return data_bitflips;
+
+ bitflips_threshold -= data_bitflips;
+
+ ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
+ if (ecc_bitflips < 0)
+ return ecc_bitflips;
+
+ bitflips_threshold -= ecc_bitflips;
+
+ extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
+ bitflips_threshold);
+ if (extraoob_bitflips < 0)
+ return extraoob_bitflips;
+
+ if (data_bitflips)
+ memset(data, 0xff, datalen);
+
+ if (ecc_bitflips)
+ memset(ecc, 0xff, ecclen);
+
+ if (extraoob_bitflips)
+ memset(extraoob, 0xff, extraooblen);
+
+ return data_bitflips + ecc_bitflips + extraoob_bitflips;
+}
+EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
+
+/**
* nanddev_isbad() - Check if a block is bad
* @nand: NAND device
* @pos: position pointing to the block we want to check
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -2784,137 +2784,6 @@ int nand_set_features(struct nand_chip *
}
/**
- * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
- * @buf: buffer to test
- * @len: buffer length
- * @bitflips_threshold: maximum number of bitflips
- *
- * Check if a buffer contains only 0xff, which means the underlying region
- * has been erased and is ready to be programmed.
- * The bitflips_threshold specify the maximum number of bitflips before
- * considering the region is not erased.
- * Note: The logic of this function has been extracted from the memweight
- * implementation, except that nand_check_erased_buf function exit before
- * testing the whole buffer if the number of bitflips exceed the
- * bitflips_threshold value.
- *
- * Returns a positive number of bitflips less than or equal to
- * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
- * threshold.
- */
-static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
-{
- const unsigned char *bitmap = buf;
- int bitflips = 0;
- int weight;
-
- for (; len && ((uintptr_t)bitmap) % sizeof(long);
- len--, bitmap++) {
- weight = hweight8(*bitmap);
- bitflips += BITS_PER_BYTE - weight;
- if (unlikely(bitflips > bitflips_threshold))
- return -EBADMSG;
- }
-
- for (; len >= sizeof(long);
- len -= sizeof(long), bitmap += sizeof(long)) {
- unsigned long d = *((unsigned long *)bitmap);
- if (d == ~0UL)
- continue;
- weight = hweight_long(d);
- bitflips += BITS_PER_LONG - weight;
- if (unlikely(bitflips > bitflips_threshold))
- return -EBADMSG;
- }
-
- for (; len > 0; len--, bitmap++) {
- weight = hweight8(*bitmap);
- bitflips += BITS_PER_BYTE - weight;
- if (unlikely(bitflips > bitflips_threshold))
- return -EBADMSG;
- }
-
- return bitflips;
-}
-
-/**
- * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
- * 0xff data
- * @data: data buffer to test
- * @datalen: data length
- * @ecc: ECC buffer
- * @ecclen: ECC length
- * @extraoob: extra OOB buffer
- * @extraooblen: extra OOB length
- * @bitflips_threshold: maximum number of bitflips
- *
- * Check if a data buffer and its associated ECC and OOB data contains only
- * 0xff pattern, which means the underlying region has been erased and is
- * ready to be programmed.
- * The bitflips_threshold specify the maximum number of bitflips before
- * considering the region as not erased.
- *
- * Note:
- * 1/ ECC algorithms are working on pre-defined block sizes which are usually
- * different from the NAND page size. When fixing bitflips, ECC engines will
- * report the number of errors per chunk, and the NAND core infrastructure
- * expect you to return the maximum number of bitflips for the whole page.
- * This is why you should always use this function on a single chunk and
- * not on the whole page. After checking each chunk you should update your
- * max_bitflips value accordingly.
- * 2/ When checking for bitflips in erased pages you should not only check
- * the payload data but also their associated ECC data, because a user might
- * have programmed almost all bits to 1 but a few. In this case, we
- * shouldn't consider the chunk as erased, and checking ECC bytes prevent
- * this case.
- * 3/ The extraoob argument is optional, and should be used if some of your OOB
- * data are protected by the ECC engine.
- * It could also be used if you support subpages and want to attach some
- * extra OOB data to an ECC chunk.
- *
- * Returns a positive number of bitflips less than or equal to
- * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
- * threshold. In case of success, the passed buffers are filled with 0xff.
- */
-int nand_check_erased_ecc_chunk(void *data, int datalen,
- void *ecc, int ecclen,
- void *extraoob, int extraooblen,
- int bitflips_threshold)
-{
- int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
-
- data_bitflips = nand_check_erased_buf(data, datalen,
- bitflips_threshold);
- if (data_bitflips < 0)
- return data_bitflips;
-
- bitflips_threshold -= data_bitflips;
-
- ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
- if (ecc_bitflips < 0)
- return ecc_bitflips;
-
- bitflips_threshold -= ecc_bitflips;
-
- extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
- bitflips_threshold);
- if (extraoob_bitflips < 0)
- return extraoob_bitflips;
-
- if (data_bitflips)
- memset(data, 0xff, datalen);
-
- if (ecc_bitflips)
- memset(ecc, 0xff, ecclen);
-
- if (extraoob_bitflips)
- memset(extraoob, 0xff, extraooblen);
-
- return data_bitflips + ecc_bitflips + extraoob_bitflips;
-}
-EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
-
-/**
* nand_read_page_raw_notsupp - dummy read raw page function
* @chip: nand chip info structure
* @buf: buffer to store read data
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1136,4 +1136,9 @@ static inline bool nanddev_bbt_is_initia
int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo);
int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len);
+int nand_check_erased_ecc_chunk(void *data, int datalen,
+ void *ecc, int ecclen,
+ void *extraoob, int extraooblen,
+ int threshold);
+
#endif /* __LINUX_MTD_NAND_H */
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -1519,11 +1519,6 @@ int rawnand_sw_bch_correct(struct nand_c
unsigned char *read_ecc, unsigned char *calc_ecc);
void rawnand_sw_bch_cleanup(struct nand_chip *chip);
-int nand_check_erased_ecc_chunk(void *data, int datalen,
- void *ecc, int ecclen,
- void *extraoob, int extraooblen,
- int threshold);
-
int nand_ecc_choose_conf(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail);

View File

@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/property.h>
#include "phy_rtl826xb_patch.h"
#include "rtk_phylib_rtl826xb.h"
@ -15,6 +16,10 @@
#define REALTEK_PHY_ID_RTL8264B 0x001CC813
#define REALTEK_PHY_ID_RTL8264 0x001CCAF2
#define REALTEK_SERDES_GLOBAL_CFG 0x1c
#define REALTEK_HSO_INV BIT(7)
#define REALTEK_HSI_INV BIT(6)
static int rtl826xb_get_features(struct phy_device *phydev)
{
int ret;
@ -41,6 +46,7 @@ static int rtl826xb_get_features(struct phy_device *phydev)
static int rtl826xb_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
struct rtk_phy_priv *priv = NULL;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct rtk_phy_priv), GFP_KERNEL);
@ -55,6 +61,7 @@ static int rtl826xb_probe(struct phy_device *phydev)
priv->phytype = (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N) ? (RTK_PHYLIB_RTL8261N) : (RTK_PHYLIB_RTL8264B);
priv->isBasePort = (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N) ? (1) : (((phydev->mdio.addr % 4) == 0) ? (1) : (0));
priv->pnswap_tx = device_property_read_bool(dev, "realtek,pnswap-tx");
phydev->priv = priv;
return 0;
@ -62,6 +69,7 @@ static int rtl826xb_probe(struct phy_device *phydev)
static int rtkphy_config_init(struct phy_device *phydev)
{
struct rtk_phy_priv *priv = phydev->priv;
int ret = 0;
switch (phydev->drv->phy_id)
{
@ -117,6 +125,11 @@ static int rtkphy_config_init(struct phy_device *phydev)
}
#endif
if (priv->pnswap_tx)
phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
REALTEK_SERDES_GLOBAL_CFG,
REALTEK_HSO_INV);
break;
default:
phydev_err(phydev, "%s:%u Unknow phy_id: 0x%X\n", __FUNCTION__, __LINE__, phydev->drv->phy_id);

View File

@ -8,6 +8,8 @@
#define __RTK_PHYLIB_H
#if defined(RTK_PHYDRV_IN_LINUX)
#include <linux/types.h>
#include "type.h"
#include "rtk_phylib_def.h"
#else
@ -48,6 +50,8 @@ struct rtk_phy_priv {
rtk_phylib_phy_t phytype;
uint8 isBasePort;
rt_phy_patch_db_t *patch;
bool pnswap_tx;
};
#if defined(RTK_PHYDRV_IN_LINUX)

View File

@ -1,2 +1,2 @@
LINUX_VERSION-6.6 = .107
LINUX_KERNEL_HASH-6.6.107 = c9b73017d3c7867b9c69a542e5318620cf2b14ed23d52f6aeaaee8aded9ee447
LINUX_VERSION-6.6 = .108
LINUX_KERNEL_HASH-6.6.108 = 601cd332aa695d16607b353feff369b4a0b36d111be077e8af54bdd41e1968a6

View File

@ -5,9 +5,13 @@ define Device/mikrotik_nor
KERNEL_NAME := vmlinux
KERNEL := kernel-bin | append-dtb-elf
IMAGES = sysupgrade.bin
IMAGES += sysupgrade-v7.bin
IMAGE/sysupgrade.bin := append-kernel | yaffs-filesystem -L | \
pad-to $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | \
check-size | append-metadata
IMAGE/sysupgrade-v7.bin := append-kernel | kernel-pack-npk | \
yaffs-filesystem -L | pad-to $$$$(BLOCKSIZE) | \
append-rootfs | pad-rootfs | check-size | append-metadata
endef
define Device/mikrotik_nand

View File

@ -10,7 +10,7 @@ BOARDNAME:=Cavium Networks Octeon
FEATURES:=squashfs ramdisk pci usb
CPU_TYPE:=octeonplus
KERNEL_PATCHVER:=6.6
KERNEL_PATCHVER:=6.12
define Target/Description
Build firmware images for Cavium Networks Octeon-based boards.

View File

@ -49,10 +49,12 @@ CONFIG_CPU_RMAP=y
CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_HUGEPAGES=y
CONFIG_CPU_SUPPORTS_VZ=y
CONFIG_CRAMFS=y
CONFIG_CRC16=y
CONFIG_CRYPTO_CRC32=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
@ -65,6 +67,7 @@ CONFIG_CRYPTO_LIB_UTILS=y
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
CONFIG_DEBUG_INFO_NONE=y
CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE=y
CONFIG_DMA_NEED_SYNC=y
CONFIG_DNOTIFY=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
@ -164,6 +167,7 @@ CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SRCU_NMI_SAFE=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
# CONFIG_NET_DSA_KS8995 is not set
CONFIG_NET_EGRESS=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_INGRESS=y
@ -208,10 +212,8 @@ CONFIG_PHYLIB=y
CONFIG_PHYLIB_LEDS=y
CONFIG_PHYLINK=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
CONFIG_PREEMPT_NONE_BUILD=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_QCOM_NET_PHYLIB=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_RANDSTRUCT_NONE=y
@ -238,6 +240,7 @@ CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPI_OCTEON=y
CONFIG_SPLIT_PTE_PTLOCKS=y
CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
CONFIG_SWIOTLB=y
CONFIG_SWPHY=y

View File

@ -0,0 +1,116 @@
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -15,6 +15,7 @@
#include <linux/libfdt.h>
#include <asm/octeon/octeon.h>
+#include <asm/octeon/octeon-platform.h>
#include <asm/octeon/cvmx-helper-board.h>
#ifdef CONFIG_USB
--- a/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c
@@ -34,6 +34,7 @@
#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-interrupt-decodes.h>
#include <asm/octeon/cvmx-gmxx-defs.h>
#include <asm/octeon/cvmx-pcsx-defs.h>
#include <asm/octeon/cvmx-pcsxx-defs.h>
--- a/arch/mips/cavium-octeon/executive/cvmx-helper-errata.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-errata.c
@@ -39,6 +39,8 @@
#include <asm/octeon/cvmx-helper-jtag.h>
+#include <asm/octeon/cvmx-helper-errata.h>
+
/**
* Due to errata G-720, the 2nd order CDR circuit on CN52XX pass
* 1 doesn't work properly. The following code disables 2nd order
--- a/arch/mips/cavium-octeon/smp.c
+++ b/arch/mips/cavium-octeon/smp.c
@@ -92,6 +92,8 @@ static irqreturn_t mailbox_interrupt(int
return IRQ_HANDLED;
}
+void octeon_send_ipi_single(int cpu, unsigned int action);
+
/*
* Cause the function described by call_data to be executed on the passed
* cpu. When the function has finished, increment the finished field of
--- a/arch/mips/mm/c-octeon.c
+++ b/arch/mips/mm/c-octeon.c
@@ -16,6 +16,7 @@
#include <asm/bcache.h>
#include <asm/bootinfo.h>
+#include <asm/c-octeon.h>
#include <asm/cacheops.h>
#include <asm/cpu-features.h>
#include <asm/cpu-type.h>
--- /dev/null
+++ b/arch/mips/include/asm/c-octeon.h
@@ -0,0 +1,9 @@
+#ifndef __C_OCTEON_H__
+#define __C_OCTEON_H__
+
+extern int register_co_cache_error_notifier(struct notifier_block *nb);
+extern int unregister_co_cache_error_notifier(struct notifier_block *nb);
+extern void cache_parity_error_octeon_recoverable(void);
+extern void cache_parity_error_octeon_non_recoverable(void);
+
+#endif
--- /dev/null
+++ b/drivers/watchdog/octeon-wdt-main.h
@@ -0,0 +1,5 @@
+#ifdef CONFIG_OCTEON_WDT
+
+extern void octeon_wdt_nmi_stage3(u64 reg[32]);
+
+#endif
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -64,6 +64,8 @@
#include <asm/octeon/cvmx-ciu2-defs.h>
#include <asm/octeon/cvmx-rst-defs.h>
+#include "octeon-wdt-main.h"
+
/* Watchdog interrupt major block number (8 MSBs of intsn) */
#define WD_BLOCK_NUMBER 0x01
--- a/arch/mips/include/asm/octeon/pci-octeon.h
+++ b/arch/mips/include/asm/octeon/pci-octeon.h
@@ -24,6 +24,12 @@
*/
#define CVMX_PCIE_BAR1_RC_BASE (1ull << 41)
+extern int octeon_pci_pcibios_map_irq(const struct pci_dev *dev, u8 slot,
+ u8 pin);
+
+extern int octeon_pcie_pcibios_map_irq(const struct pci_dev *dev, u8 slot,
+ u8 pin);
+
/*
* pcibios_map_irq() is defined inside pci-octeon.c. All it does is
* call the Octeon specific version pointed to by this variable. This
--- /dev/null
+++ b/arch/mips/include/asm/octeon/cvmx-interrupt-decodes.h
@@ -0,0 +1,6 @@
+#ifndef __CVMX_INTERRUPT_DECODES_H__
+#define __CVMX_INTERRUPT_DECODES_H__
+
+extern void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block);
+
+#endif
--- /dev/null
+++ b/arch/mips/include/asm/octeon/octeon-platform.h
@@ -0,0 +1,6 @@
+#ifndef __OCTEON_PLATFORM_H__
+#define __OCTEON_PLATFORM_H__
+
+extern void octeon_fill_mac_addresses(void);
+
+#endif

View File

@ -10,7 +10,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1090,6 +1090,10 @@ config MIPS_MSC
@@ -1132,6 +1132,10 @@ config MIPS_MSC
config SYNC_R4K
bool

View File

@ -21,7 +21,7 @@
+ return 0;
+
+ if (replace) {
+ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline));
+ strscpy(arcs_cmdline, p, sizeof(arcs_cmdline));
+ } else {
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));

View File

@ -1,6 +1,6 @@
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -775,7 +775,7 @@ int __init octeon_prune_device_tree(void
@@ -776,7 +776,7 @@ int __init octeon_prune_device_tree(void
if (fdt_check_header(initial_boot_params))
panic("Corrupt Device Tree.");

View File

@ -18,7 +18,7 @@
ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_ITUS_SHIELD)
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -636,6 +636,7 @@ static void __init octeon_rx_tx_delay(in
@@ -637,6 +637,7 @@ static void __init octeon_rx_tx_delay(in
}
break;
case CVMX_BOARD_TYPE_UBNT_E100:

View File

@ -17,7 +17,7 @@ Date: Tue Jun 17 13:58:19 2025 +0200
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -1133,6 +1133,41 @@ end_led:
@@ -1134,6 +1134,41 @@ end_led:
}
#endif
@ -61,14 +61,14 @@ Date: Tue Jun 17 13:58:19 2025 +0200
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -1168,6 +1168,7 @@ void __init prom_free_prom_memory(void)
}
}
@@ -43,6 +43,7 @@
#include <asm/time.h>
+int __init ubnt_prune_device_tree(void);
void __init octeon_fill_mac_addresses(void);
#include <asm/octeon/octeon.h>
+#include <asm/octeon/octeon-platform.h>
#include <asm/octeon/pci-octeon.h>
#include <asm/octeon/cvmx-rst-defs.h>
void __init device_tree_init(void)
@@ -1207,6 +1208,9 @@ void __init device_tree_init(void)
octeon_prune_device_tree();
pr_info("Using internal Device Tree.\n");
@ -79,3 +79,12 @@ Date: Tue Jun 17 13:58:19 2025 +0200
if (fill_mac)
octeon_fill_mac_addresses();
unflatten_and_copy_device_tree();
--- a/arch/mips/include/asm/octeon/octeon-platform.h
+++ b/arch/mips/include/asm/octeon/octeon-platform.h
@@ -2,5 +2,6 @@
#define __OCTEON_PLATFORM_H__
extern void octeon_fill_mac_addresses(void);
+extern int ubnt_prune_device_tree(void);
#endif

View File

@ -2120,6 +2120,10 @@ define Device/MikroTik
IMAGE/sysupgrade.bin := append-kernel | yaffs-filesystem -L | \
pad-to $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size | \
append-metadata
IMAGES += sysupgrade-v7.bin
IMAGE/sysupgrade-v7.bin := append-kernel | kernel-pack-npk | \
yaffs-filesystem -L | pad-to $$$$(BLOCKSIZE) | \
append-rootfs | pad-rootfs | check-size | append-metadata
endef
define Device/mikrotik_ltap-2hnd

View File

@ -63,6 +63,7 @@
reg = <24>;
label = "lan9";
pcs-handle = <&serdes4>;
phy-handle = <&phy24>;
phy-mode = "1000base-x";
managed = "in-band-status";
sfp = <&sfp0>;
@ -72,6 +73,7 @@
reg = <26>;
label = "lan10";
pcs-handle = <&serdes5>;
phy-handle = <&phy26>;
phy-mode = "1000base-x";
managed = "in-band-status";
sfp = <&sfp1>;

View File

@ -55,6 +55,13 @@
#size-cells = <1>;
ranges = <0x0 0x18000000 0x20000>;
ecc0: ecc@1a600 {
compatible = "realtek,rtl9301-ecc";
reg = <0x1a600 0x54>;
status = "disabled";
};
intc: interrupt-controller@3000 {
compatible = "realtek,rtl9300-intc", "realtek,rtl-intc";
reg = <0x3000 0x18>, <0x3018 0x18>;

View File

@ -90,6 +90,13 @@
#size-cells = <1>;
ranges = <0x0 0x18000000 0x20000>;
ecc0: ecc@1a600 {
compatible = "realtek,rtl9301-ecc";
reg = <0x1a600 0x54>;
status = "disabled";
};
spi0: spi@1200 {
status = "okay";

View File

@ -334,6 +334,9 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
if (of_property_read_u32(dn, "reg", &pn))
continue;
pcs_node = of_parse_phandle(dn, "pcs-handle", 0);
priv->pcs[pn] = rtpcs_create(priv->dev, pcs_node, pn);
phy_node = of_parse_phandle(dn, "phy-handle", 0);
if (!phy_node) {
if (pn != priv->cpu_port)
@ -341,9 +344,6 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
continue;
}
pcs_node = of_parse_phandle(dn, "pcs-handle", 0);
priv->pcs[pn] = rtpcs_create(priv->dev, pcs_node, pn);
/*
* TODO: phylink_pcs was completely converted to the standalone PCS driver - see
* rtpcs_create(). Nevertheless the DSA driver still relies on the info about the

View File

@ -711,32 +711,33 @@ struct rtl838x_l2_entry {
u16 vid;
u16 rvid;
u8 port;
bool valid;
enum l2_entry_type type;
bool is_static;
bool is_ip_mc;
bool is_ipv6_mc;
bool block_da;
bool block_sa;
bool suspended;
bool next_hop;
bool valid:1;
bool is_static:1;
bool is_ip_mc:1;
bool is_ipv6_mc:1;
bool block_da:1;
bool block_sa:1;
bool suspended:1;
bool next_hop:1;
bool is_trunk:1;
bool nh_vlan_target:1; /* Only RTL83xx: VLAN used for next hop */
int age;
u8 trunk;
bool is_trunk;
u8 stack_dev;
u16 mc_portmask_index;
u32 mc_gip;
u32 mc_sip;
u16 mc_mac_index;
u16 nh_route_id;
bool nh_vlan_target; /* Only RTL83xx: VLAN used for next hop */
/* The following is only valid on RTL931x */
bool is_open_flow;
bool is_pe_forward;
bool is_local_forward;
bool is_remote_forward;
bool is_l2_tunnel;
bool is_open_flow:1;
bool is_pe_forward:1;
bool is_local_forward:1;
bool is_remote_forward:1;
bool is_l2_tunnel:1;
bool hash_msb:1;
int l2_tunnel_id;
int l2_tunnel_list_id;
};

View File

@ -558,6 +558,7 @@ static void rtl931x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
r[0] |= e->is_open_flow ? BIT(30) : 0;
r[0] |= e->is_pe_forward ? BIT(29) : 0;
r[0] |= e->hash_msb ? BIT(28): 0;
r[2] = e->next_hop ? BIT(30) : 0;
r[0] |= (e->rvid & 0xfff) << 16;
@ -675,11 +676,22 @@ static void rtl931x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_
u32 r[4];
struct table_reg *q = rtl_table_get(RTL9310_TBL_0, 0);
u32 idx = (0 << 14) | (hash << 2) | pos; /* Access SRAM, with hash and at pos in bucket */
int hash_algo_id;
pr_debug("%s: hash %d, pos %d\n", __func__, hash, pos);
pr_debug("%s: index %d -> mac %02x:%02x:%02x:%02x:%02x:%02x\n", __func__, idx,
e->mac[0], e->mac[1], e->mac[2], e->mac[3],e->mac[4],e->mac[5]);
if (idx < 0x4000)
hash_algo_id = sw_r32(RTL931X_L2_CTRL) & BIT(0);
else
hash_algo_id = (sw_r32(RTL931X_L2_CTRL) & BIT(1)) >> 1;
if (hash_algo_id == 0)
e->hash_msb = (e->rvid >> 2) & 0x1;
else
e->hash_msb = (e->rvid >> 11) & 0x1;
rtl931x_fill_l2_row(r, e);
pr_debug("%s: %d: %08x %08x %08x\n", __func__, idx, r[0], r[1], r[2]);

View File

@ -0,0 +1,521 @@
From 3148d0e5b1c5733d69ec51b70c8280e46488750a Mon Sep 17 00:00:00 2001
From: Markus Stockhausen <markus.stockhausen@gmx.de>
Date: Fri, 19 Sep 2025 03:52:01 -0400
Subject: mtd: nand: realtek-ecc: Add Realtek external ECC engine support
The Realtek RTl93xx switch SoC series has a built in ECC controller
that can provide BCH6 or BCH12 over 512 data and 6 tag bytes. It
generates 10 (BCH6) or 20 (BCH12) bytes of parity.
This engine will most likely work in conjunction with the Realtek
spi-mem based NAND controller but can work on its own. Therefore
the initial implementation will be of type external.
Remark! The engine can support any data blocks that are multiples
of 512 bytes. For now limit it to data+oob layouts that have been
analyzed from existing devices. This way it keeps compatibility
and pre-existing vendor data can be read.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/Kconfig | 8 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/ecc-realtek.c | 464 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 473 insertions(+)
create mode 100644 drivers/mtd/nand/ecc-realtek.c
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -65,6 +65,14 @@ config MTD_NAND_ECC_MEDIATEK
help
This enables support for the hardware ECC engine from Mediatek.
+config MTD_NAND_ECC_REALTEK
+ tristate "Realtek RTL93xx hardware ECC engine"
+ depends on HAS_IOMEM
+ depends on MACH_REALTEK_RTL || COMPILE_TEST
+ select MTD_NAND_ECC
+ help
+ This enables support for the hardware ECC engine from Realtek.
+
endmenu
endmenu
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -2,6 +2,7 @@
nandcore-objs := core.o bbt.o
obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
+obj-$(CONFIG_MTD_NAND_ECC_REALTEK) += ecc-realtek.o
obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o
ifeq ($(CONFIG_SPI_QPIC_SNAND),y)
--- /dev/null
+++ b/drivers/mtd/nand/ecc-realtek.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for Realtek hardware ECC engine in RTL93xx SoCs
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dma-mapping.h>
+#include <linux/mtd/nand.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/*
+ * The Realtek ECC engine has two operation modes.
+ *
+ * - BCH6 : Generate 10 ECC bytes from 512 data bytes plus 6 free bytes
+ * - BCH12 : Generate 20 ECC bytes from 512 data bytes plus 6 free bytes
+ *
+ * It can run for arbitrary NAND flash chips with different block and OOB sizes. Currently there
+ * are only two known devices in the wild that have NAND flash and make use of this ECC engine
+ * (Linksys LGS328C & LGS352C). To keep compatibility with vendor firmware, new modes can only
+ * be added when new data layouts have been analyzed. For now allow BCH6 on flash with 2048 byte
+ * blocks and 64 bytes oob.
+ *
+ * This driver aligns with kernel ECC naming conventions. Neverthless a short notice on the
+ * Realtek naming conventions for the different structures in the OOB area.
+ *
+ * - BBI : Bad block indicator. The first two bytes of OOB. Protected by ECC!
+ * - tag : 6 User/free bytes. First tag "contains" 2 bytes BBI. Protected by ECC!
+ * - syndrome : ECC/parity bytes
+ *
+ * Altogether this gives currently the following block layout.
+ *
+ * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+
+ * | 512 | 512 | 512 | 512 | 2 | 4 | 6 | 6 | 6 | 10 | 10 | 10 | 10 |
+ * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+
+ * | data | data | data | data | BBI | free | free | free | free | ECC | ECC | ECC | ECC |
+ * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+
+ */
+
+#define RTL_ECC_ALLOWED_PAGE_SIZE 2048
+#define RTL_ECC_ALLOWED_OOB_SIZE 64
+#define RTL_ECC_ALLOWED_STRENGTH 6
+
+#define RTL_ECC_BLOCK_SIZE 512
+#define RTL_ECC_FREE_SIZE 6
+#define RTL_ECC_PARITY_SIZE_BCH6 10
+#define RTL_ECC_PARITY_SIZE_BCH12 20
+
+/*
+ * The engine is fed with two DMA regions. One for data (always 512 bytes) and one for free bytes
+ * and parity (either 16 bytes for BCH6 or 26 bytes for BCH12). Start and length of each must be
+ * aligned to a multiple of 4.
+ */
+
+#define RTL_ECC_DMA_FREE_PARITY_SIZE ALIGN(RTL_ECC_FREE_SIZE + RTL_ECC_PARITY_SIZE_BCH12, 4)
+#define RTL_ECC_DMA_SIZE (RTL_ECC_BLOCK_SIZE + RTL_ECC_DMA_FREE_PARITY_SIZE)
+
+#define RTL_ECC_CFG 0x00
+#define RTL_ECC_BCH6 0
+#define RTL_ECC_BCH12 BIT(28)
+#define RTL_ECC_DMA_PRECISE BIT(12)
+#define RTL_ECC_BURST_128 GENMASK(1, 0)
+#define RTL_ECC_DMA_TRIGGER 0x08
+#define RTL_ECC_OP_DECODE 0
+#define RTL_ECC_OP_ENCODE BIT(0)
+#define RTL_ECC_DMA_START 0x0c
+#define RTL_ECC_DMA_TAG 0x10
+#define RTL_ECC_STATUS 0x14
+#define RTL_ECC_CORR_COUNT GENMASK(19, 12)
+#define RTL_ECC_RESULT BIT(8)
+#define RTL_ECC_ALL_ONE BIT(4)
+#define RTL_ECC_OP_STATUS BIT(0)
+
+struct rtl_ecc_engine {
+ struct device *dev;
+ struct nand_ecc_engine engine;
+ struct mutex lock;
+ char *buf;
+ dma_addr_t buf_dma;
+ struct regmap *regmap;
+};
+
+struct rtl_ecc_ctx {
+ struct rtl_ecc_engine * rtlc;
+ struct nand_ecc_req_tweak_ctx req_ctx;
+ int steps;
+ int bch_mode;
+ int strength;
+ int parity_size;
+};
+
+static const struct regmap_config rtl_ecc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static inline void *nand_to_ctx(struct nand_device *nand)
+{
+ return nand->ecc.ctx.priv;
+}
+
+static inline struct rtl_ecc_engine *nand_to_rtlc(struct nand_device *nand)
+{
+ struct nand_ecc_engine *eng = nand->ecc.engine;
+
+ return container_of(eng, struct rtl_ecc_engine, engine);
+}
+
+static int rtl_ecc_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand);
+
+ if (section < 0 || section >= ctx->steps)
+ return -ERANGE;
+
+ oobregion->offset = ctx->steps * RTL_ECC_FREE_SIZE + section * ctx->parity_size;
+ oobregion->length = ctx->parity_size;
+
+ return 0;
+}
+
+static int rtl_ecc_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand);
+ int bbm;
+
+ if (section < 0 || section >= ctx->steps)
+ return -ERANGE;
+
+ /* reserve 2 BBM bytes in first block */
+ bbm = section ? 0 : 2;
+ oobregion->offset = section * RTL_ECC_FREE_SIZE + bbm;
+ oobregion->length = RTL_ECC_FREE_SIZE - bbm;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops rtl_ecc_ooblayout_ops = {
+ .ecc = rtl_ecc_ooblayout_ecc,
+ .free = rtl_ecc_ooblayout_free,
+};
+
+static void rtl_ecc_kick_engine(struct rtl_ecc_ctx *ctx, int operation)
+{
+ struct rtl_ecc_engine *rtlc = ctx->rtlc;
+
+ regmap_write(rtlc->regmap, RTL_ECC_CFG,
+ ctx->bch_mode | RTL_ECC_BURST_128 | RTL_ECC_DMA_PRECISE);
+
+ regmap_write(rtlc->regmap, RTL_ECC_DMA_START, rtlc->buf_dma);
+ regmap_write(rtlc->regmap, RTL_ECC_DMA_TAG, rtlc->buf_dma + RTL_ECC_BLOCK_SIZE);
+ regmap_write(rtlc->regmap, RTL_ECC_DMA_TRIGGER, operation);
+}
+
+static int rtl_ecc_wait_for_engine(struct rtl_ecc_ctx *ctx)
+{
+ struct rtl_ecc_engine *rtlc = ctx->rtlc;
+ int ret, status, bitflips;
+ bool all_one;
+
+ /*
+ * The ECC engine needs 6-8 us to encode/decode a BCH6 syndrome for 512 bytes of data
+ * and 6 free bytes. In case the NAND area has been erased and all data and oob is
+ * set to 0xff, decoding takes 30us (reason unknown). Although the engine can trigger
+ * interrupts when finished, use active polling for now. 12 us maximum wait time has
+ * proven to be a good tradeoff between performance and overhead.
+ */
+
+ ret = regmap_read_poll_timeout(rtlc->regmap, RTL_ECC_STATUS, status,
+ !(status & RTL_ECC_OP_STATUS), 12, 1000000);
+ if (ret)
+ return ret;
+
+ ret = FIELD_GET(RTL_ECC_RESULT, status);
+ all_one = FIELD_GET(RTL_ECC_ALL_ONE, status);
+ bitflips = FIELD_GET(RTL_ECC_CORR_COUNT, status);
+
+ /* For erased blocks (all bits one) error status can be ignored */
+ if (all_one)
+ ret = 0;
+
+ return ret ? -EBADMSG : bitflips;
+}
+
+static int rtl_ecc_run_engine(struct rtl_ecc_ctx *ctx, char *data, char *free,
+ char *parity, int operation)
+{
+ struct rtl_ecc_engine *rtlc = ctx->rtlc;
+ char *buf_parity = rtlc->buf + RTL_ECC_BLOCK_SIZE + RTL_ECC_FREE_SIZE;
+ char *buf_free = rtlc->buf + RTL_ECC_BLOCK_SIZE;
+ char *buf_data = rtlc->buf;
+ int ret;
+
+ mutex_lock(&rtlc->lock);
+
+ memcpy(buf_data, data, RTL_ECC_BLOCK_SIZE);
+ memcpy(buf_free, free, RTL_ECC_FREE_SIZE);
+ memcpy(buf_parity, parity, ctx->parity_size);
+
+ dma_sync_single_for_device(rtlc->dev, rtlc->buf_dma, RTL_ECC_DMA_SIZE, DMA_TO_DEVICE);
+ rtl_ecc_kick_engine(ctx, operation);
+ ret = rtl_ecc_wait_for_engine(ctx);
+ dma_sync_single_for_cpu(rtlc->dev, rtlc->buf_dma, RTL_ECC_DMA_SIZE, DMA_FROM_DEVICE);
+
+ if (ret >= 0) {
+ memcpy(data, buf_data, RTL_ECC_BLOCK_SIZE);
+ memcpy(free, buf_free, RTL_ECC_FREE_SIZE);
+ memcpy(parity, buf_parity, ctx->parity_size);
+ }
+
+ mutex_unlock(&rtlc->lock);
+
+ return ret;
+}
+
+static int rtl_ecc_prepare_io_req(struct nand_device *nand, struct nand_page_io_req *req)
+{
+ struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand);
+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand);
+ char *data, *free, *parity;
+ int ret = 0;
+
+ if (req->mode == MTD_OPS_RAW)
+ return 0;
+
+ nand_ecc_tweak_req(&ctx->req_ctx, req);
+
+ if (req->type == NAND_PAGE_READ)
+ return 0;
+
+ free = req->oobbuf.in;
+ data = req->databuf.in;
+ parity = req->oobbuf.in + ctx->steps * RTL_ECC_FREE_SIZE;
+
+ for (int i = 0; i < ctx->steps; i++) {
+ ret |= rtl_ecc_run_engine(ctx, data, free, parity, RTL_ECC_OP_ENCODE);
+
+ free += RTL_ECC_FREE_SIZE;
+ data += RTL_ECC_BLOCK_SIZE;
+ parity += ctx->parity_size;
+ }
+
+ if (unlikely(ret))
+ dev_dbg(rtlc->dev, "ECC calculation failed\n");
+
+ return ret ? -EBADMSG : 0;
+}
+
+static int rtl_ecc_finish_io_req(struct nand_device *nand, struct nand_page_io_req *req)
+{
+ struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand);
+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand);
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+ char *data, *free, *parity;
+ bool failure = false;
+ int bitflips = 0;
+
+ if (req->mode == MTD_OPS_RAW)
+ return 0;
+
+ if (req->type == NAND_PAGE_WRITE) {
+ nand_ecc_restore_req(&ctx->req_ctx, req);
+ return 0;
+ }
+
+ free = req->oobbuf.in;
+ data = req->databuf.in;
+ parity = req->oobbuf.in + ctx->steps * RTL_ECC_FREE_SIZE;
+
+ for (int i = 0 ; i < ctx->steps; i++) {
+ int ret = rtl_ecc_run_engine(ctx, data, free, parity, RTL_ECC_OP_DECODE);
+
+ if (unlikely(ret < 0))
+ /* ECC totally fails for bitflips in erased blocks */
+ ret = nand_check_erased_ecc_chunk(data, RTL_ECC_BLOCK_SIZE,
+ parity, ctx->parity_size,
+ free, RTL_ECC_FREE_SIZE,
+ ctx->strength);
+ if (unlikely(ret < 0)) {
+ failure = true;
+ mtd->ecc_stats.failed++;
+ } else {
+ mtd->ecc_stats.corrected += ret;
+ bitflips = max_t(unsigned int, bitflips, ret);
+ }
+
+ free += RTL_ECC_FREE_SIZE;
+ data += RTL_ECC_BLOCK_SIZE;
+ parity += ctx->parity_size;
+ }
+
+ nand_ecc_restore_req(&ctx->req_ctx, req);
+
+ if (unlikely(failure))
+ dev_dbg(rtlc->dev, "ECC correction failed\n");
+ else if (unlikely(bitflips > 2))
+ dev_dbg(rtlc->dev, "%d bitflips detected\n", bitflips);
+
+ return failure ? -EBADMSG : bitflips;
+}
+
+static int rtl_ecc_check_support(struct nand_device *nand)
+{
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+ struct device *dev = nand->ecc.engine->dev;
+
+ if (mtd->oobsize != RTL_ECC_ALLOWED_OOB_SIZE ||
+ mtd->writesize != RTL_ECC_ALLOWED_PAGE_SIZE) {
+ dev_err(dev, "only flash geometry data=%d, oob=%d supported\n",
+ RTL_ECC_ALLOWED_PAGE_SIZE, RTL_ECC_ALLOWED_OOB_SIZE);
+ return -EINVAL;
+ }
+
+ if (nand->ecc.user_conf.algo != NAND_ECC_ALGO_BCH ||
+ nand->ecc.user_conf.strength != RTL_ECC_ALLOWED_STRENGTH ||
+ nand->ecc.user_conf.placement != NAND_ECC_PLACEMENT_OOB ||
+ nand->ecc.user_conf.step_size != RTL_ECC_BLOCK_SIZE) {
+ dev_err(dev, "only algo=bch, strength=%d, placement=oob, step=%d supported\n",
+ RTL_ECC_ALLOWED_STRENGTH, RTL_ECC_BLOCK_SIZE);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rtl_ecc_init_ctx(struct nand_device *nand)
+{
+ struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
+ struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand);
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+ int strength = nand->ecc.user_conf.strength;
+ struct device *dev = nand->ecc.engine->dev;
+ struct rtl_ecc_ctx *ctx;
+ int ret;
+
+ ret = rtl_ecc_check_support(nand);
+ if (ret)
+ return ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ nand->ecc.ctx.priv = ctx;
+ mtd_set_ooblayout(mtd, &rtl_ecc_ooblayout_ops);
+
+ conf->algo = NAND_ECC_ALGO_BCH;
+ conf->strength = strength;
+ conf->step_size = RTL_ECC_BLOCK_SIZE;
+ conf->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+
+ ctx->rtlc = rtlc;
+ ctx->steps = mtd->writesize / RTL_ECC_BLOCK_SIZE;
+ ctx->strength = strength;
+ ctx->bch_mode = strength == 6 ? RTL_ECC_BCH6 : RTL_ECC_BCH12;
+ ctx->parity_size = strength == 6 ? RTL_ECC_PARITY_SIZE_BCH6 : RTL_ECC_PARITY_SIZE_BCH12;
+
+ ret = nand_ecc_init_req_tweaking(&ctx->req_ctx, nand);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "using bch%d with geometry data=%dx%d, free=%dx6, parity=%dx%d",
+ conf->strength, ctx->steps, conf->step_size,
+ ctx->steps, ctx->steps, ctx->parity_size);
+
+ return 0;
+}
+
+static void rtl_ecc_cleanup_ctx(struct nand_device *nand)
+{
+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand);
+
+ if (ctx)
+ nand_ecc_cleanup_req_tweaking(&ctx->req_ctx);
+}
+
+static struct nand_ecc_engine_ops rtl_ecc_engine_ops = {
+ .init_ctx = rtl_ecc_init_ctx,
+ .cleanup_ctx = rtl_ecc_cleanup_ctx,
+ .prepare_io_req = rtl_ecc_prepare_io_req,
+ .finish_io_req = rtl_ecc_finish_io_req,
+};
+
+static int rtl_ecc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtl_ecc_engine *rtlc;
+ void __iomem *base;
+ int ret;
+
+ rtlc = devm_kzalloc(dev, sizeof(*rtlc), GFP_KERNEL);
+ if (!rtlc)
+ return -ENOMEM;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ ret = devm_mutex_init(dev, &rtlc->lock);
+ if (ret)
+ return ret;
+
+ rtlc->regmap = devm_regmap_init_mmio(dev, base, &rtl_ecc_regmap_config);
+ if (IS_ERR(rtlc->regmap))
+ return PTR_ERR(rtlc->regmap);
+
+ /*
+ * Focus on simplicity and use a preallocated DMA buffer for data exchange with the
+ * engine. For now make it a noncoherent memory model as invalidating/flushing caches
+ * is faster than reading/writing uncached memory on the known architectures.
+ */
+
+ rtlc->buf = dma_alloc_noncoherent(dev, RTL_ECC_DMA_SIZE, &rtlc->buf_dma,
+ DMA_BIDIRECTIONAL, GFP_KERNEL);
+ if (IS_ERR(rtlc->buf))
+ return PTR_ERR(rtlc->buf);
+
+ rtlc->dev = dev;
+ rtlc->engine.dev = dev;
+ rtlc->engine.ops = &rtl_ecc_engine_ops;
+ rtlc->engine.integration = NAND_ECC_ENGINE_INTEGRATION_EXTERNAL;
+
+ nand_ecc_register_on_host_hw_engine(&rtlc->engine);
+
+ platform_set_drvdata(pdev, rtlc);
+
+ return 0;
+}
+
+static void rtl_ecc_remove(struct platform_device *pdev)
+{
+ struct rtl_ecc_engine *rtlc = platform_get_drvdata(pdev);
+
+ nand_ecc_unregister_on_host_hw_engine(&rtlc->engine);
+ dma_free_noncoherent(rtlc->dev, RTL_ECC_DMA_SIZE, rtlc->buf, rtlc->buf_dma,
+ DMA_BIDIRECTIONAL);
+}
+
+static const struct of_device_id rtl_ecc_of_ids[] = {
+ {
+ .compatible = "realtek,rtl9301-ecc",
+ },
+ { /* sentinel */ },
+};
+
+static struct platform_driver rtl_ecc_driver = {
+ .driver = {
+ .name = "rtl-nand-ecc-engine",
+ .of_match_table = rtl_ecc_of_ids,
+ },
+ .probe = rtl_ecc_probe,
+ .remove = rtl_ecc_remove,
+};
+module_platform_driver(rtl_ecc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Markus Stockhausen <markus.stockhausen@gmx.de>");
+MODULE_DESCRIPTION("Realtek NAND hardware ECC controller");

View File

@ -158,6 +158,8 @@ CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_JEDECPROBE=y
# CONFIG_MTD_NAND_ECC_REALTEK is not set
# CONFIG_MTD_SPI_NAND is not set
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_BRNIMAGE_FW=y
CONFIG_MTD_SPLIT_EVA_FW=y

View File

@ -161,6 +161,8 @@ CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_JEDECPROBE=y
# CONFIG_MTD_NAND_ECC_REALTEK is not set
# CONFIG_MTD_SPI_NAND is not set
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_BRNIMAGE_FW=y
CONFIG_MTD_SPLIT_EVA_FW=y

View File

@ -145,6 +145,7 @@ CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_JEDECPROBE=y
# CONFIG_MTD_NAND_ECC_REALTEK is not set
# CONFIG_MTD_SPI_NAND is not set
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_BRNIMAGE_FW=y

View File

@ -145,6 +145,7 @@ CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_NAND_ECC_REALTEK=y
CONFIG_MTD_SPI_NAND=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_BRNIMAGE_FW=y

View File

@ -156,6 +156,7 @@ CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_JEDECPROBE=y
# CONFIG_MTD_NAND_ECC_REALTEK is not set
# CONFIG_MTD_SPI_NAND is not set
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_BRNIMAGE_FW=y

View File

@ -156,6 +156,7 @@ CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_NAND_ECC_REALTEK=y
CONFIG_MTD_SPI_NAND=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_BRNIMAGE_FW=y

View File

@ -9,10 +9,10 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=expat
PKG_CPE_ID:=cpe:/a:libexpat:libexpat
PKG_VERSION:=2.7.1
PKG_VERSION:=2.7.3
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_HASH:=0cce2e6e69b327fc607b8ff264f4b66bdf71ead55a87ffd5f3143f535f15cfa2
PKG_HASH:=821ac9710d2c073eaf13e1b1895a9c9aa66c1157a99635c639fbff65cdbdd732
PKG_SOURCE_URL:=https://github.com/libexpat/libexpat/releases/download/R_$(subst .,_,$(PKG_VERSION))
HOST_BUILD_PARALLEL:=1

View File

@ -11,9 +11,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/firmware-utils.git
PKG_SOURCE_DATE:=2025-08-03
PKG_SOURCE_VERSION:=950f83405a935395492d61c9972b5e5ca826eeee
PKG_MIRROR_HASH:=19f5b7547dc6f9460e25183c83d55aca9d1f18148466c09b64504a64379a34ae
PKG_SOURCE_DATE:=2025-09-23
PKG_SOURCE_VERSION:=7e6f69b444c33a6ca4e9efb98832820e3d8e87ba
PKG_MIRROR_HASH:=714053067b2b64689a6db9de0f49d1ce4fa20d9824d8f08e3c598b903eed8c03
include $(INCLUDE_DIR)/host-build.mk
include $(INCLUDE_DIR)/cmake.mk