Commit Graph
70774 Commits
Author SHA1 Message Date
John Audia af76d8e9b3 kernel: bump 6.18 to 6.18.47
Changelog: https://cdn.kernel.org/pub/linux/kernel/v6.x/ChangeLog-6.18.47

All patches automatically rebased via update_kernel.sh

Build system: x86/64
Build-tested: x86/64-glibc
Run-tested: x86/64-glibc

Signed-off-by: John Audia <therealgraysky@proton.me>
Link: https://github.com/openwrt/openwrt/pull/24800
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-16 11:43:33 +02:00
John Audia 87e5289908 kernel: bump 6.18 to 6.18.46
Changelog: https://cdn.kernel.org/pub/linux/kernel/v6.x/ChangeLog-6.18.46

All patches automatically rebased via update_kernel.sh

Build system: x86/64
Build-tested: x86/64-glibc
Run-tested: x86/64-glibc

Signed-off-by: John Audia <therealgraysky@proton.me>
Link: https://github.com/openwrt/openwrt/pull/24800
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-16 11:43:33 +02:00
John Audia 5edc3c1b8a kernel: bump 6.18 to 6.18.45
Changelog: https://cdn.kernel.org/pub/linux/kernel/v6.x/ChangeLog-6.18.45

Manually rebased:
  generic/pending-6.18/804-nvmem-core-support-mac-base-fixed-layout-cells.patch
  generic/pending-6.18/809-01-nvmem-core-generalize-mac-base-cells-handling.patch

Removed upstreamed:
  bcm53xx/patches-6.18/353-ARM-dts-bcm-ns-fix-PCIe-controller-2-second-interrup.patch[1]

All other patches automatically rebased via update_kernel.sh

1. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v6.18.45&id=9e5e88fbfc87d6a9edf72f8febc94061a6d0395e

Build system: x86/64
Build-tested: x86/64-glibc
Run-tested: x86/64-glibc

Signed-off-by: John Audia <therealgraysky@proton.me>
Link: https://github.com/openwrt/openwrt/pull/24800
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-16 11:43:33 +02:00
Jonas Jelonek 7657f1cf92 realtek: pcs: rtl93xx: share PLL reconfiguration
RTL930x and RTL931x use the same sequence to move a running SerDes to
another PLL. Consolidate the implementations using the existing variant
operations for deactivation, PLL selection, mode restoration and
activation.

Switch RTL930x to the same valid assumption that RTL931x already uses:
Assume that the requested PLL is always the opposite one to be able to
drop the last remaining invariant between both, to unify both
implementations.

While at it, make the RTL930x set_power helper return its error instead
of discarding it silently.

Assisted-by: ChatGPT (OpenAI GPT-5.6 Sol)
Link: https://github.com/openwrt/openwrt/pull/25176
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
2026-09-16 10:51:22 +02:00
Jonas Jelonek b236706ab7 realtek: pcs: rtl930x: fail mode setup on CMU errors
Continuing after CMU setup fails leaves the SerDes without a usable clock
configuration. Propagate the error from config_hw_mode() so pcs_config()
aborts before programming and activating the target mode.

Assisted-by: ChatGPT (OpenAI GPT-5.6 Sol)
Link: https://github.com/openwrt/openwrt/pull/25176
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
2026-09-16 10:51:22 +02:00
Jonas Jelonek 665d187ee1 realtek: pcs: rtl930x: configure CMU for all modes
USXGMII may fail to come up on SerDes lanes that previously ran SGMII
or 1000Base-X. Updating the MAC mode alone does not reliably reconfigure
the analog clock path.

Run CMU configuration for every active RTL930x mode and check clock
readiness after programming the target mode. Preserve the existing choice
between MAC-driven and IP-driven mode setup. Restore PLL-migrated neighbors
through their saved mode and USXGMII submode so MAC-driven modes no longer
depend on stale IP mode state.

This marks a breaking point of our understanding of the SerDes setup
under RTL930x hardware. While we assumed so far that MAC-driven modes
are entirely setup and controlled by the MAC setup, this appears to be
not true based on the issue. More likely is that default or preset
configuration on certain SerDes happens to be correct for all our needs
so far. But if we drive the those SerDes with modes the SDK hasn't
intended, such issues will surface.

Link: https://github.com/openwrt/openwrt/issues/25065
Assisted-by: ChatGPT (OpenAI GPT-5.6 Sol)
Link: https://github.com/openwrt/openwrt/pull/25176
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
2026-09-16 10:51:21 +02:00
Jonas Jelonek 70a51c7619 realtek: arch: add compatible for RTL9302B
Add the RTL9302B variant as a dedicated compatible to the board support
patch for properly setup on devices with this SoC.

Link: https://github.com/openwrt/openwrt/pull/25208
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
2026-09-16 10:50:32 +02:00
Rosen Penev b572e055fc mediatek: use libdeflate for gzip
Shrinks size slightly.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/24148
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
2026-09-16 10:32:10 +02:00
Rosen Penev b7d0a5ce14 gpio-button-hotplug: gate off gpio_request_one
Upstream is working towards making GPIOLIB_LEGACY optional. Get ahead of
that by gating off such code as is done upstream.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/24985
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
2026-09-16 10:22:06 +02:00
Daniel Golle 0f8cceb469 generic: mikrotik: avoid 64-bit module breakage
The use of a modulo operation on 64-bit integers broke the build on
32-bit targets which do not provide such operations.

Seen on the buildbots as:
mips-openwrt-linux-musl-ld: drivers/mtd/parsers/routerbootpart.o:
in function `routerboot_partitions_parse':
drivers/mtd/parsers/routerbootpart.c:
(.text.routerboot_partitions_parse+0x58c):
undefined reference to `__umoddi3'

Fix this by using mtd_mod_by_eb() instead of open-coding the alginment
check.

Fixes: ada1dcb2b4 ("generic: mikrotik: size RouterBoot partitions so they are usable")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2026-09-15 22:34:33 +01:00
Gennaro Cimmino 3e566e9c9b realtek: l3: rtl930x: bind an egress interface to its VLAN
Found while working through https://github.com/openwrt/openwrt/issues/25129.

otto_l3_alloc_egress_intf() looks for an egress interface that already
carries the router MAC and reuses it, whatever VLAN that interface was
made for. The MAC it matches on is the one of the netdev the route
points at, and a VLAN device inherits it from the bridge, so on a router
with several VLANs they all carry the same one: the first VLAN to ask
takes an interface and every other VLAN is handed that one.

That matters because the entry behind it holds DST_VID, the VLAN the
routed packet is sent into, so every VLAN but the first would forward
into the first one's domain. The vendor SDK keys interfaces the same way
this patch does - dal_longan_l3_intf_create() stores one interface index
per VID and writes that VID as the egress DST_VID - and in that mode it
sizes the table at 64, the number of source MAC slots, which is what the
array here is indexed by.

Match on the VLAN as well as the MAC, and keep the descriptors in the
array that struct otto_l3_ctrl already had for them, declared and never
used. Two dev_dbg lines are added with it, because the allocator had no
output at all and the choice it makes is not visible anywhere else.

An interface is still never released - nothing frees one today - so with
this change a box that creates and destroys VLAN interfaces burns a slot
each time and has 64 of them.

Measured on a Hasivo S1100W-8XGT-SE (RTL9303), kernel 6.18.44, with
CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD=y, from a clean boot: an
address on the bridge VLAN, then an interface on VLAN 30 and a route
through it.

  add IPv4 route 192.168.1.1/32 (VLAN 1, MAC 00:82:44:xx:xx:xx)
  new egress interface 0 for VLAN 1
  add IPv4 route 192.168.1.0/24 (VLAN 1, MAC 00:82:44:xx:xx:xx)
  reusing egress interface 0 for VLAN 1
  add IPv4 route 10.79.0.1/32 (VLAN 30, MAC 00:82:44:xx:xx:xx)
  new egress interface 1 for VLAN 30
  add IPv4 route 10.79.0.0/24 (VLAN 30, MAC 00:82:44:xx:xx:xx)
  reusing egress interface 1 for VLAN 30

The same MAC on both VLANs is what the third column shows. By
inspection, with the VLAN out of the comparison the search ends at the
first entry holding that MAC, which is interface 0; the DST_VID that
would then be used is not something I measured on the wire.

RTL930x only: the interface table and its MAC table are written through
ops set in otto_l3_930x_cfg alone, under a symbol no target config sets,
and the call sits in the set_router_mac branch, an op no other family
has.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25204
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 20:58:04 +02:00
Daniel Golle 75ccc4822b mac80211: bump PKG_RELEASE
Dropping the rt2x00 MTD EEPROM patch changes the modules the package
builds, so bump the release for users to receive the update.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2026-09-15 18:03:36 +01:00
Daniel Golle 2bbdbb8b43 mac80211: rt2x00: add missing patch headers
Eight of the rt2x00 patches either carry no From/Date/Subject header at
all or lack the leading "From <sha> Mon Sep 17 00:00:00 2001" line, so
"git am" cannot apply them and the contribution checks reject them. Take
the author, date and subject of each from the commit which first added
it to this tree.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2026-09-15 18:03:36 +01:00
Daniel Golle 8f071273d7 mac80211: rt2x00: drop MTD EEPROM loading
No device tree uses ralink,mtd-eeprom any more, and since the move from
rt2x00eeprom.c into rt2800lib.c the code is guarded by SOC_RT288X and
SOC_RT305X, so it was compiled out on the only two boards that still
asked for it and dead everywhere else. It also lost its
<linux/mtd/mtd.h> include in that move, which breaks the rt305x build
with implicit declarations of get_mtd_device_nm(), mtd_read() and
put_mtd_device(). Drop the patch; nvmem cells cover every remaining
user.

Fixes: bf44cb5fb0 ("mac80211: update to version 7.2")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2026-09-15 18:03:36 +01:00
Daniel Golle 11c75d9520 bmips: hg556a-c: load wifi EEPROM from NVMEM
Describe the Ralink EEPROM as a cell of the cal_data partition and point
the card at it, so the board no longer needs ralink,mtd-eeprom.

Commit 72f43ac220 ("bmips: huawei-hg556a-c: use nvmem for wifi
eeprom") tried this before and was reverted in b270580dea because the
card came up without calibration data. That attempt named the cell
"calibration", while rt2800_read_eeprom_nvmem() looks up "eeprom", so
the driver never found it and the byte order it blamed was not involved:
both paths copy the same 512 bytes from the same offset.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2026-09-15 18:03:36 +01:00
Daniel Golle 0772ee3e09 lantiq: arv7525pw: load wifi EEPROM from NVMEM
The board is the last lantiq device still using ralink,mtd-eeprom, which
commit 926991329b ("lantiq: convert ralink,mtd-eeprom to nvmem") left
behind. Describe the EEPROM as a cell of the board_config partition and
point the Ralink card at it. Both paths copy the same 512 bytes from the
same offset into the driver, so the data the driver sees is unchanged.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2026-09-15 18:03:36 +01:00
Daniel Golle 1f7eb34c53 odhcpd: make the full variant displace odhcpd-ipv6only
Both variants install the same files, so selecting both breaks image
assembly. Let odhcpd provide odhcpd-ipv6only and mark the latter
DEFAULT_VARIANT: the generated conflict demotes odhcpd-ipv6only when
odhcpd is selected, and under apk the versioned provide enforces a
single instance. Imagebuilder users pass -odhcpd-ipv6only alongside
odhcpd.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2026-09-15 17:40:48 +01:00
George Moussalem 0d754ca55b qualcommax: ipq807x: Flatten USB controller nodes
Flatten usb controller nodes and update to using latest bindings and
flattened driver approach.

In addition, fix indentation of properties in both nodes.

link: https://lore.kernel.org/r/20260906-ipq-flatten-usb-v3-9-13e4e0f63123@outlook.com

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/25038
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 18:35:11 +02:00
George Moussalem c935b04218 qualcommax: ipq807x: move DR mode to board DTS
Both controllers are DRD capable, but DR mode currently set to host mode
in the SoC dtsi. Unset it in the SoC dtsi and set it as host mode in the
hk01 board DTS file.

link: https://lore.kernel.org/r/20260906-ipq-flatten-usb-v3-8-13e4e0f63123@outlook.com

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/25038
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 18:35:11 +02:00
George Moussalem 6f038ccc67 qualcommax: ipq60xx: Flatten USB controller nodes
Flatten usb controller nodes and update to using latest bindings and
flattened driver approach.

link: https://lore.kernel.org/r/20260906-ipq-flatten-usb-v3-7-13e4e0f63123@outlook.com

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/25038
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 18:35:11 +02:00
George Moussalem d7ad3dce34 qualcommax: ipq60xx: move DR mode to board DTS
DRD capable controllers are currently set to host mode in the SoC dtsi.
Unset it in the SoC dtsi and set it as host mode in the board DTS.

link: https://lore.kernel.org/r/20260906-ipq-flatten-usb-v3-6-13e4e0f63123@outlook.com

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/25038
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 18:35:11 +02:00
George Moussalem 807daedab6 qualcommax: ipq50xx: Update to latest patches for USB3 support
Update to latest patches sent for upstream review for USB3 support.

This PHY found in IPQ5332 and IPQ5018 SoCs is actually a multi-purpose
PCIe/USB3 combo PHY. The driver was initially created for PCIe PHY
support only. As such, rename the driver and its symbol and generalize
the driver to reflect that it is a PCIe and USB3 combo PHY driver and
add USB3 support.

The PCIe and USB physical pads are muxed and selection is done via a
control register in TCSR.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/25038
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 18:35:11 +02:00
George Moussalem 619db5a936 qualcommax: ipq50xx: update to latest patch to flatten USB controller node
Update to the latest patch sent upstream to flatten the USB controller
node. Also set the required reference clock (mock_utmi) rate, away from
the patch to add clocks required for USB3 support.

link: https://lore.kernel.org/r/20260906-ipq-flatten-usb-v3-3-13e4e0f63123@outlook.com

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/25038
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 18:35:11 +02:00
George Moussalem cf3fe920b9 qualcommax: usb: dwc3: Allow glue layer to pass reference clock rate
Add ability to pass the reference clock rate from the glue layer to the
DWC3 core driver. The core calculates the reference clock period and
frame length adjustment based on the reference clock rate.

In the flattened snsp-dwc3 model, it is currently not possible to pass a
reference clock that differs from the default since:
commit 613a2e655d4d ("usb: dwc3: core: Expose core driver as library")

The new glue layers (incl. Qualcomm's) set the ignore_clocks_and_resets
flag in dwc3_probe_data to true, which disables the core driver's clock
management, thus it also doesn't acquire the reference clock from the
devicetree needed in dwc3_ref_clk_period.

There's an existing DT property 'snps,ref-clock-period-ns', but that's
been deprecated. In addition, basing the rate from the period is often
not accurate enough to derive the frame length adjustment value.

This prevents moving chipsets such as IPQ5018, IPQ6018, IPQ5332, IPQ5424
and IPQ9574 with a reference clock rate that computes values for the
period and frame length adjustment different from the hardware default
from moving to the flattened model.

So, add ability to set the reference clock rate in dwc3_probe_data, then
have the core obtain the clock rate and use that to calculate the
required period and frame length adjustment.

This fixes USB2 mode on the IPQ50xx platform.

link: https://lore.kernel.org/r/20260906-ipq-flatten-usb-v3-1-13e4e0f63123@outlook.com
link: https://lore.kernel.org/r/20260906-ipq-flatten-usb-v3-2-13e4e0f63123@outlook.com

Fixes: 	409bf967e4 ("qualcommax: ipq50xx: add support for USB3")
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/25038
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 18:35:11 +02:00
Zoltan HERPAI 980becf1da imx: add support for Olimex i.MX8MP-SOM-EVB
This adds support for an i.MX8-based system-on-module + EVB board.

CPU:      NXP i.MX8MP @ 1600MHz (quad-core A53)
Memory:   4Gb
PCI:      1x PCIe M.2 2280 slot
Ethernet: 2x GE with Micrel PHY (no MAC in EEPROM)
USB:      2x 3.0
UART:     separate UARTs for the A53 and the M7 cores
Storage:  microSD slot, eMMC headers
Misc:     2KByte EEPROM (at24), audio via ES8328 (unsupported), 2x CAN, HDMI
Power:    5VDC

 - Patches refreshed as required
 - The cortexa53 subtarget selects Micrel PHY from now on
 - u-boot added for the board

Installation:
  Use the standard installation to an SD-card by writing out the
  squashfs image (openwrt-imx-cortexa53-olimex_imx8mp-som-squashfs-img.gz)
  to it.

Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
2026-09-15 18:32:14 +02:00
Zoltan HERPAI 4a07d09446 imx: image: add BOOT_SCRIPT and UBOOT to DEVICE_VARS
Currently all images are generated with the same "last" BOOT_SCRIPT
setting in the image Makefile, which is the Kontron one. Allow
per-device overriding by these variables to DEVICE_VARS.

Fixes: https://github.com/openwrt/openwrt/commit/07a5e432c83aa5c5b8ef21caf84fc1d051dfcadc
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
2026-09-15 18:32:13 +02:00
Gennaro Cimmino b2d4d802ab realtek: l3: do not add a second route for one destination
Every route add that reaches the driver arrives as
FIB_EVENT_ENTRY_REPLACE, the one behind ip route replace included, and
otto_l3_fib_add_v4() always allocates a fresh route object and a fresh
table row. Changing the gateway of an offloaded route therefore leaves
the old row in place, pointing at the old gateway, and the delete that
follows takes out only the row the second add made:

  ip route add 10.30.0.0/24 via 192.168.1.250      one row
  ip route replace 10.30.0.0/24 via 192.168.1.249  two rows, same dst
  ip route del 10.30.0.0/24                        the first row stays

The switch is left with a valid row forwarding that prefix to the old
gateway, and the first route object is leaked with its id, its next hop,
its packet counter and its PIE rule. It is not forgotten, either: it
stays in the hash under the old gateway, so every neighbour update for
that gateway writes the stale row back into hardware.

Keep the routes on a list beside the hash, look the destination up
before allocating, and take the old route out the way the delete path
does, which is now a helper the two share. The lookup carries the table
id as well, because the same prefix in two routing tables is two routes,
and it takes the entry type, so the IPv6 side needs a caller rather than
a second function.

Runs on RTL839x and, with the offload symbol on, RTL930x; RTL838x and
RTL931x return early in the notifier because cfg->setup is NULL, and
RTL839x is compile-tested only.

Functionally tested on a Hasivo S1100W-8XGT-SE (RTL9303), kernel
6.18.44, with CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD=y: the sequence
above now leaves one row after the replace and none after the delete,
and the same holds for ip route append followed by a flush.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25199
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 16:36:59 +02:00
Gennaro Cimmino dff4c3c0f7 realtek: l3: name the four route entry types
The two bits the hardware keeps in every route entry select IPv4 or IPv6
and unicast or multicast, and the driver spelled them 0, 1, 2 and 3 in
nine switch statements and three assignments, each with a comment saying
what the number meant.

Give them names next to the route actions they sit beside in the entry,
and drop the comments the names replace.

No functional change.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25199
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 16:36:59 +02:00
Gennaro Cimmino 2795383aaf realtek: l3: do not release what a pending route never got
A route whose gateway has not resolved yet carries none of the resources
otto_l3_fib_del_v4() releases: the L2 next hop, the packet counter and
the PIE rule all come from otto_l3_nexthop_update(), which only runs once
the neighbour is valid. Deleting such a route hands the sentinels
straight to the hardware helpers.

The PIE rule is the one that hurts. Its id is -1 until the rule is
added, and rtl930x_pie_rule_rm() passes it on without a test:

  rtl930x_pie_rule_del(priv, -1, -1)  ->  (-1 << 1) | (-1 << 12) | BIT(0)

writes 0xffffffff into RTL930X_PIE_CLR_CTRL and then waits for a clear
that names rule 2047, and clear_bit(-1, priv->pie_use_bm) turns into bit
0xffffffff, half a gigabyte past a 288-byte array. RTL839x has the same
two lines. The next hop id and the packet counter are zero from the
allocation, so the same call reads L2 bucket 0 and releases counter 0,
which another rule may own.

Adding a route through a gateway that never answers and deleting it is
enough, and it is what a routing daemon does when a peer goes away. On a
RTL9303 with the driver's debug output enabled:

  rtl83xx-switch ...: need to wait
  rtl83xx-switch ...: found a route with id 4, nh-id 0
  rtl83xx-switch ...: unknown nexthop, id 0
  rtl83xx-switch ...: releasing packet counter 0
  rtl930x_pie_rule_del: from -1 to -1

Test the id the driver already uses to mean "this route has a rule", and
give the counter the same -1 sentinel the rule id has, which
rtldsa_packet_cntr_free() already refuses.

Runs on RTL839x and, with the offload symbol on, RTL930x; RTL838x and
RTL931x return early in the notifier because cfg->setup is NULL. On
RTL839x the counter matters more than on RTL930x: there the allocator
hands out index 0, so releasing it returns a counter another rule is
still using.

Functionally tested on a Hasivo S1100W-8XGT-SE (RTL9303), kernel
6.18.44, with CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD=y: the same
sequence no longer reaches pie_rule_del or the next hop, the counter
release shows the sentinel, and the removal still reports the route as
not in hardware. RTL839x is compile-tested only.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25199
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 16:36:59 +02:00
Markus Stockhausen 63fab3bad4 realtek: dsa: fix RTL839x egress queue configuration
RTL839X_QM_PORT_QNUM contains ten packed 3-bit port fields per
register. Writing the complete register for each port therefore clears
the queue configuration of the other ports sharing that register.

Update rtl839x_set_egress_queue() to modify only the field belonging to
the requested port. Use the corrected helper during QoS initialization
for all user ports and the CPU port.

While we are here make the function static.

Assisted-by: ChatGPT (OpenAI GPT-5.6 Sol)
Link: https://github.com/openwrt/openwrt/pull/25186
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 16:09:30 +02:00
Markus Stockhausen 549c879311 realtek: dsa: move RTL93xx QoS code to qos.c
Keep the QoS implementation grouped by functionality instead of SoC
family. Move the RTL930x and RTL931x QoS initialization and helper
functions from the corresponding SoC files to qos.c.

Add qos.h for the public QoS interface and move the existing QoS
declarations out of rtl-otto.h. Mark configuration arrays that are now
local to qos.c as static.

No functional change intended.

Assisted-by: ChatGPT (OpenAI GPT-5.6 Sol)
Link: https://github.com/openwrt/openwrt/pull/25186
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 16:09:30 +02:00
Tanner Lane 1ff2a3ef77 realtek: fix MokerLink reset polarity
GPIO27 is high while the reset button is released and low while it is
pressed, so the reset line is active-low.

The original verification missed this because pressing the button caused
the device to reboot with either polarity. The test was performed on a
freshly flashed device, so the unintended factory reset was not apparent.

Declare GPIO27 active-low so short presses reboot without clearing the
configuration and long presses retain the intended factory-reset behavior.

Fixes: 7f03bc02b0 ("realtek: add support for MokerLink 10GT080M")

Signed-off-by: Tanner Lane <tannerln7@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/25172
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 13:43:19 +02:00
André Valentin ff0a961064 qualcommax: add support for MikroTik Chateau 5G R17 ax
Ordering code S53UG+5HaxD2HaxD&RG650E-EU. First MikroTik device on this
target.

Specifications:
  SoC       Qualcomm IPQ6010, 4x Cortex-A53, 864-1800 MHz
  RAM       1 GB
  Flash     128 MB NAND (QPIC), 512 KB SPI-NOR holding RouterBOOT
  Ethernet  4x 1G, Qualcomm QCA8075 (PSGMII, MDIO 0x18-0x1b)
            1x 2.5G, Qualcomm QCA8081 (2500base-x, MDIO 0x00)
  WLAN      IPQ6010 integrated, 2x2 2.4 GHz + 2x2 5 GHz, ath11k
  Modem     Quectel RG650E-EU 5G, USB 2c7c:0122, internal bus
  USB       1x 3.0 type A, external
  LEDs      system RGB, eth, wlan, 5x LTE signal strength
  Buttons   reset, mode, WPS
  Power     12-28 VDC barrel jack, 27 W max

Serial console: header silkscreened SPI/UART, reachable only with the case
open. Viewed from the back the square pad is pin 10, bottom right:

  pin 3  RX, router input     pin 5  GND     pin 8  TX, router output

115200 8N1, 3.3 V TTL, no flow control. Do not connect VCC.

Flash layout:
  NAND mtd0  0x0000000-0x0800000    8 MB  "kernel", yaffs
       mtd1  0x0800000-0x8000000  120 MB  "ubi"
  SPI-NOR, RouterBoot partition at 0x2c0000, 512 KB, 64 KB erase blocks:
       +0x00000 bootloader, +0x20000 hard_config, +0x30000 second stage,
       +0x40000 soft_config, +0x70000 device tree

Installation: boot the initramfs image over RouterBOOT etherboot (reset
button, or boot_device=ethonce plus commit through the rb_softconfig sysfs
interface), then sysupgrade. sysupgrade writes the kernel with yafut,
since yaffs keeps metadata and ECC in the OOB area where mtd cannot reach.
It erases the partition first: from the factory 4.38 of the 8 MB are in
use, and yaffs frees the old blocks only after writing. RouterBOOT is
never written, so etherboot and Netinstall stay available.

Device tree notes:
  - soc_version_major is normally injected by the QSDK U-Boot; without it
    the CPR driver hits a BUG_ON.
  - Socket labels run opposite to the PSGMII lane order, verified socket
    by socket.
  - MAC addresses come from hard_config, one per port as the factory
    allocates them (mac_count 7: 5 ethernet, 2 radios). Without them the
    ports inherit the EDMA conduit address, which qca_edma.c only randomises
    as a fallback when no port describes one.
  - The PSGMII SerDes runs at 300 mV as Qualcomm's SSDK does, not the
    600 mV qca807x.c defaults to.
  - The watchdog is left disabled: a WDT bite is an abrupt hardware warm
    reset that skips the WCSS teardown and hangs the board in SBL1 (the
    IPQ6018 warm-reboot path). procd feeds it fine in normal operation, but
    a bite comes back stuck rather than recovering the soft hang.
  - PCIe appeared to stop the Ethernet transmit path and stays off; the
    mPCIe slot is unused since the modem is on USB. That bisect rests on
    a single boot per variant and does not carry, given that the PSGMII
    calibration fails intermittently with a similar symptom.

Board data comes out of RouterBOOT rather than out of ipq-wifi. This
unit's own board data file sits in hard_config tag 0x16 as 5100 bytes of
LZ77; rb_hardconfig decompresses it and exports a 64 KiB blob that is a
complete BDF - same 01 00 04 04 magic as the ipq-wifi files, a valid
header checksum, this unit's factory MAC addresses instead of the Qualcomm
defaults, and the chainmasks of the two 2x2 radios. RouterOS uses exactly
that: localphy-qcom reads it through getHcfgBdwlan() ("Bdwlan: bdwlan
found in hrdcfg") and only falls back to a generic <board>.bdwlan when
hard_config carries none.

The ath11k firmware hotplug script (11-ath11k-caldata) hands the blob to
the driver. ath11k first looks for a board-2.bin container and, once no
entry matches, falls back to ath11k_core_fetch_board_data_api_1() with
ATH11K_DEFAULT_BOARD_FILE; it also asks for cal-ahb-c000000.wifi.bin. The
same 64 KiB blob answers every one of those requests through
caldata_sysfsload_from_file, fed straight into the sysfs firmware
interface without being written to /lib/firmware. board.bin is what we
serve because it takes a bare BDF - no container to build and no length
arithmetic to keep in sync with the calibration variant. The blob is
passed through unchanged: the firmware validates it beyond the header
checksum and aborts with "phyrf_bdf.c:472 Assertion 0 failed" on any
modification.

uqmi does not fully drive the RG650E-EU: it only obtains a client ID for
UIM, while DMS, NAS and WDS answer "Failed to connect to service". A
libqmi based connection manager is needed for a data session.

Signed-off-by: André Valentin <avalentin@marcant.net>
Link: https://github.com/openwrt/openwrt/pull/24335
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 13:21:07 +02:00
André Valentin 6b85badadc qualcommax: add mikrotik-lzma-loader for RouterBOOT devices
RouterBOOT loads bare unsigned ARM64 ELF images only, neither FIT nor
uImage, and the yaffs kernel partition on these MikroTik devices is 8 MiB
while the raw arm64 image is around 14 MiB. This self-extracting loader
wraps the LZMA compressed kernel and the DTB in a single PT_LOAD segment,
decompresses them at runtime and jumps to the kernel. The entry sequence
follows MikroTik's own loader as found in the flash dump, noted in
start.S. It installs an identity mapping before decompressing so it does
not run entirely uncached, and keeps its stack below the load address
because RouterBOOT loads only filesz bytes and the memory beyond that is
not usable that early.

src/LzmaDecode.[ch] are the LZMA SDK 4.21 decoder by Igor Pavlov, taken
unmodified under their own license (LGPL or CPL at your choice, plus the
linking exception); everything else is written for this loader. Hence
PKG_LICENSE lists both licenses and PKG_LICENSE_FILES points at
src/LzmaDecode.c.

Signed-off-by: André Valentin <avalentin@marcant.net>
Link: https://github.com/openwrt/openwrt/pull/24335
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 13:21:07 +02:00
André Valentin ada1dcb2b4 generic: mikrotik: size RouterBoot partitions so they are usable
Two fixes to the RouterBoot partition handling, both found on a MikroTik
Chateau 5G R17 ax but neither device specific.

hard_config is not guaranteed to fit within RB_BLOCK_SIZE. On this board
the tag list spans 5576 bytes, because the WLAN calibration tag alone
carries 5100 bytes of LZ77 compressed data, so truncating the partition
makes that tag unreadable. Walk the tag list to its terminating null node
and size the partition accordingly. The result never shrinks below
RB_BLOCK_SIZE, so devices whose tag list already fits are unaffected.

soft_config carries the boot settings and is the one RouterBoot segment
meant to be written, but at RB_BLOCK_SIZE (4 KiB) on a flash with 64 KiB
erase blocks MTD always forces it read-only. Grow it to a full erase
block where the space is free, checked against the following partition so
that erasing it cannot destroy a neighbour.

That growth alone would break the checksum, because rb_softconfig derives
everything from the partition size while RouterBoot validates the CRC32
over its own 4 KiB. Introduce RB_SC_CFG_SIZE and keep reads, CRC and write
back within it; the erase still covers the whole partition.

With both in place, writing boot_device followed by commit persists across
a reboot and "ethonce" triggers a real etherboot.

Signed-off-by: André Valentin <avalentin@marcant.net>
Link: https://github.com/openwrt/openwrt/pull/24335
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 13:21:07 +02:00
Gennaro Cimmino 3a2230382f realtek: l3: do not read a route back before programming it
otto_l3_nexthop_update() starts each route with route_read(ctrl, r->id,
r), which fills the route object from the table row at that index. For a
host route the index is wrong to begin with: host ids start at
MAX_ROUTES and the prefix route table has 512 rows, so
otto_table_index_ok() refuses the access and warns.

For a prefix route the index is right and the read is worse. The object
is the one the FIB just described, so a row left behind by an earlier
route replaces its destination and prefix length, and the row is then
written back from the object. On a RTL9303 with row 3 still holding a
deleted 10.1.2.0/24, adding 10.0.0.0/8 through the same gateway took id
3, read the stale row and programmed itself as the deleted route:

  ... add IPv4 route 10.0.0.0/8 via 192.168.1.x
  ... id: 3, ip 192.168.1.x
  ... index 3 is valid: 1
  ... GW: 10.1.2.0, prefix_len: 24

Drop the read. The destination and the prefix length come from the FIB,
the next hop id from the route id, and valid, action, type and hit are
assigned right after it. Two sets of fields were being carried over from
the row and now come from the route object, which is zeroed when it is
allocated: switch_mac_id on RTL839x, and the TTL and QoS bits on
RTL930x. Nothing in the driver ever sets them, so they were already zero
in any row this driver wrote; they differ only for a row programmed by
something else, and carrying a stale row's values is part of what this
fixes.

Runs on RTL839x and, with the offload symbol on, RTL930x. The RTL930x
side was exercised on a Hasivo S1100W-8XGT-SE, kernel 6.18.44: two
routes added through one gateway each keep their own destination.
RTL839x is compile-tested only.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25194
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 11:40:10 +02:00
Gennaro Cimmino 3fafb65de7 realtek: l3: rtl930x: remove a prefix route from its own row
otto_l3_nexthop_update() writes a prefix route at its own id, but
removal asked otto_l3_930x_route_lookup_hw() where it was. That search
keys on the masked destination rather than on the route, so any stored
network that covers the address answers, and the answer went straight
into route_write() with the valid bit down.

On a RTL9303 with 10.0.0.0/8 at row 2 and 10.1.2.0/24 at row 3, both
through one gateway, deleting the /24 cleared the /8:

  ... searching for 10.1.2.0
  ... found: 1, index: 2
  ... Got id for prefix route: 2

The table was left holding the route that had just been deleted, while
the one still in the FIB was gone. The hardware answers with the lowest
matching row, which is also why the /24 could not be found afterwards.

Look at the row the route was written at, and fall back to the search
only when the route is not there - checking what it returns, the way the
SDK does around the same lookup: _dal_longan_l3_routeEntry_find()
re-reads the index, compares it with the route, and scans linearly when
it does not match.

RTL930x only: route_lookup_hw is set in otto_l3_930x_cfg alone and the
branch it guards does not run on the other families.

Functionally tested on a Hasivo S1100W-8XGT-SE (RTL9303), kernel
6.18.44, with CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD=y: deleting the
/24 now takes row 3, its own, and leaves 10.0.0.0/8 in place.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25194
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 11:40:10 +02:00
Gennaro Cimmino 2d21547582 realtek: l3: do not treat a missing port as port 0
otto_l3_port_dev_lower_find() walks the lower devices of the interface a
route or a neighbour points at and reports the first port of this switch
it finds, or the error rtl83xx_port_is_under() returned for the last
lower it looked at. The walk does not run when the interface has no
lower devices at all, and the result started at 0, which is a port
number, so a route over a tunnel or a PPP interface passed the test that
is there to keep it out.

Start from the same error the walk reports for a device that is not a
port of this switch. Both callers use the result only as that gate:
otto_l3_fib_add_v4() refuses the route and names the interface, and the
netevent notifier ignores the neighbour.

A DSA user port is not affected: its conduit is one of its lower
devices, so the walk already answered for it. No-op on RTL838x and
RTL931x, whose notifiers return early because cfg->setup is NULL.
Compile-tested only.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25194
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 11:40:10 +02:00
Gennaro Cimmino b9bbb562b7 realtek: l3: do not delete a route the FIB did not ask for
otto_l3_fib_del_v4() looks the gateway up in the routes table, which
holds every route behind that gateway, and walks the list for the one
whose destination and prefix length match. The walk has no failure
branch, and rhl_for_each_entry_rcu() leaves its cursor on the last
element it visited rather than clearing it, so a route that is not in
the list deletes whichever route came last: its next hop is removed, its
packet counter released, its PIE rule deleted, its hardware entry
invalidated and the object freed, while the FIB still has it.

Deleting a route the driver never saw added is enough to get there.
register_fib_notifier() is called without a dump callback, so a route
that predates the probe is missing from the table but still produces a
delete event; an add refused for a missing switch port, or for a full
table, leaves the same hole.

Say which route was not found and leave the table alone.

Runs on RTL839x and, with the offload symbol on, RTL930x; RTL838x and
RTL931x return early in the notifier because cfg->setup is NULL.
Compile-tested only.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25194
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 11:40:10 +02:00
Gennaro Cimmino 2337fa244e realtek: l3: refuse a route id the table cannot hold
find_first_zero_bit() returns the size it was given when every bit is
set, and neither route allocator tests for that. On a full table the id
becomes MAX_ROUTES or MAX_HOST_ROUTES and set_bit() writes one word past
the bitmap: the two bitmaps sit next to each other in struct
otto_l3_ctrl, followed by the interface array, so overflowing the prefix
one marks host route slot 0 as used and overflowing the host one sets a
bit in the first interface pointer.

A prefix route id is also the row the route is written at, so it goes on
to ask for row 512 of a 512-row table; otto_table_index_ok() refuses the
access and warns once per boot, while otto_l3_fib_add_v4() reports
success and marks the route offloaded.

Say the table is full and return NULL, which the caller already handles:
it turns a failed allocation into -ENOSPC.

No-op on RTL838x and RTL931x, whose notifiers return early because
cfg->setup is NULL. Compile-tested only: reaching either branch takes
512 prefix or 1536 host routes offloaded at once, which the bench cannot
produce.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25194
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 11:40:10 +02:00
Jonas Köppeler 7f4f824691 generic: backport sch_cake fix for tin clearing on rate adjust
Backport upstream commit a3729e0df005 ("net/sched: sch_cake: skip
clearing unused tins during rate adjustment"), which landed in v7.2.

cake_configure_rates() is called from the dequeue path with
rate_adjust=true, where cake_clear_tin() overwrites q->cur_tin and
q->cur_flow while cake_dequeue() is using them, and purging the unused
tins adds overhead to the hot path. Skipping the loop restores loaded
latency to pre-15c2715a5264 levels; on IPQ8074A in besteffort mode the
loaded latency drops from ~470 ms to ~4 ms in Flent's tcp_nup test.

Refresh the sync_time debugfs hack patch, whose hunks shift by two
lines.

Signed-off-by: Jonas Köppeler <j.koeppeler@tu-berlin.de>
Link: https://github.com/openwrt/openwrt/pull/25182
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-15 10:07:52 +02:00
Gennaro Cimmino 036f629142 realtek: l3: rtl930x: write only host routes into the host table
otto_l3_fib_add_v4() programs a host route entry for every route without
a gateway, whatever its prefix length. A connected subnet is not a host
route: the entry it gets describes the network address, which nothing
sends to, and it goes into the table the removal path searches only for
routes allocated as host routes - so it stays behind when the interface
goes down, and the previous patch is what keeps it from accumulating.

Write the entry only for the routes the host table is for. The route
object already knows: otto_l3_host_route_alloc() is used exactly when
the prefix length is 32 and the family has a host route table, and it is
the only place that sets is_host_route.

RTL930x only: the block sits inside the set_router_mac test, and that
op, like host_route_write and find_slot, is set in otto_l3_930x_cfg
alone, under a symbol no target config sets. RTL839x, the one other
family that reaches this function, does not enter the block at all.

Measured on a Hasivo S1100W-8XGT-SE (RTL9303), kernel 6.18.44, with
CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD=y: the /24 of the lan bridge
takes no host table row at all, and twelve ifdown/ifup cycles of that
interface leave the table holding only the /32 of the interface address.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25187
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 10:06:47 +02:00
Gennaro Cimmino d6a38f407b realtek: l3: rtl930x: reuse the slot of a connected route
otto_l3_fib_add_v4() writes every route without a gateway into the host
route table, whatever its prefix length, while otto_l3_route_remove()
clears a host entry only for a route allocated as a host route, which
means a prefix length of 32. A connected subnet therefore leaves its
entry behind when the interface goes down. That part is older than the
recent fixes; what the search fix below changed is that placement now
returns free slots rather than the head of the bucket, so the next ifup
takes a fresh one instead of overwriting the stale entry. A destination
has six slots in each of the two hash tables, and once those twelve are
taken the subnet is not offloaded at all:

  rtl83xx-switch ...: no slot for host route 192.168.1.0

Ask for the entry the route already holds before asking for a free one,
the way otto_l3_nexthop_update() does, so one destination keeps one
entry. A miss costs up to twelve table reads on the add path. Two routes
that share a destination address share the entry again, the last writer
winning: a /31 link and the local /32 the kernel installs beside it are
the case to know about.

The entry is still not cleared when the route goes away, so renumbering
leaves one behind per destination: nothing in the route object records
that a prefix route was written into the host table, and the removal
path does not know to look for it. That needs a change of its own.

Measured on a Hasivo S1100W-8XGT-SE (RTL9303), kernel 6.18.44, with
CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD=y: entries reported by the
debugfs dump for the /24 of the lan bridge, counted after each of twelve
ifdown/ifup cycles of that interface.

  883ebad9ba, before the series   1, unchanged
  current main                    2, 3, 4 ... 12, then "no slot"
  with this patch                 1, unchanged

RTL930x only: find_slot() and host_route_write() are set in
otto_l3_930x_cfg alone, and only under a symbol that no target config
sets, so a stock build does not reach this path at all.

Fixes: 4344b47ebc ("realtek: l3: rtl930x: test the slot that was read")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25187
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-15 10:06:47 +02:00
Zoltan HERPAI 11c64908c1 uboot-mxs: bump to 2026.04
Compile-tested: all mxs boards
Runtime-tested: Olinuxino Micro, I2SE Duckbill

While at it, rework the Duckbill series to compile on 2026.04.

Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
2026-09-14 22:11:20 +02:00
Gennaro Cimmino d92ff769b5 realtek: l3: rtl930x: reuse the slot a host route holds
otto_l3_nexthop_update() walks every route that shares the gateway, and
the routes table is keyed on the gateway address, so adding one route
reprocesses all the others behind it. Each of them asked find_slot() for
somewhere to put a route and, now that the search reports free slots
rather than the first address of the bucket, got a fresh one every time.

On a RTL9303, three /32 routes through one gateway left seventeen host
entries behind: the same destination written again on each event until
the bucket filled, then carried into the second hash table. Before the
search was fixed the duplicate was invisible, because every write landed
on the same address and overwrote the previous one.

Ask for the route's own entry first and fall back to a free slot only
when it is not there yet. A bucket that is genuinely full now returns -1
where it could not before, so both placement sites say so instead of
writing at a negative index.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25170
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-14 21:45:55 +02:00
Gennaro Cimmino 4344b47ebc realtek: l3: rtl930x: test the slot that was read
otto_l3_930x_find_slot() probed the host route table and then looked
at the caller's route instead of the entry it had just read. The
placement test asked rt->attr.valid, which both call sites set to true
right before calling, so the first address probed was always returned:
of the 6144 host route slots only the 512 bucket heads of the first
table were reachable, and a second route in a bucket overwrote the
first. The lookup test compared route_entry.dst_ip, which
otto_l3_930x_host_route_read() does not touch when the entry is
invalid or is not IPv4 unicast, so it could match an address the
reader never wrote.

Ask the entry that was read: an empty slot for placement, and for a
lookup a valid entry of the same type whose destination matches. IPv6
unicast destinations are compared with ipv6_addr_equal() instead of
through the IPv4 field.

Measured on an RTL9303 (Hasivo S1100W-8XGT-SE): two /32 host routes
hashing to bucket 281 both ended up at logical index 1686 before this
patch. With it each route takes a slot of its own, which is also what
exposed the duplicate writes the next patch removes.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25170
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-14 21:45:55 +02:00
Gennaro Cimmino 522cb4b864 realtek: l3: rtl930x: look up the route being removed
Placing a route and deleting one are different questions. The prefix
branch of otto_l3_route_remove() already asks the right one: it looks
the route up in hardware through route_lookup_hw(), which keys on the
address and returns -1 when the search misses. The host branch beside it
asked find_slot() for somewhere to place a route, and got the head of
the bucket, which belongs to whichever route wrote there last, so
removal could clear an entry belonging to another route.

Ask for the route instead, and name it when the search misses, so the
log says which route was not cleared.

The keyed search is still the old one at this point: it compares an
address that otto_l3_930x_host_route_read() leaves untouched for an
entry that is invalid or is not IPv4 unicast, so it can answer with a
slot that holds something else. The next patch fixes that.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25170
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-14 21:45:54 +02:00
Gennaro Cimmino b52cb4b16b realtek: l3: do not write a route at a negative index
otto_l3_route_remove() asks the hardware where a route lives and then
writes the entry back with the valid bit down. Both lookups can fail.
otto_l3_930x_route_lookup_hw() returns -1 when the search misses, and
otto_l3_930x_find_slot() returns -1 for a route whose own valid flag is
still down, which is what a route that never made it into the table
looks like. The comment above the prefix branch says "If there is a HW
representation of the route, delete it", but the test is on the presence
of the ops pointer rather than on the result of the lookup, so the -1
goes straight into route_write().

Removing a route that never reached the hardware is enough to hit it: a
route whose gateway is not in ARP stays pending, so nothing was written
and the lookup misses when it is deleted.

  rtl83xx-switch ...: need to wait
  rtl83xx-switch ...: found a route with id 513, nh-id 0
  WARNING: CPU: 0 PID: 12 at drivers/soc/realtek/otto_table.c:322
           otto_table_index_ok+0x7c/0x8c
  otto_table: index -1 in table 1049, which has 8192 rows
  Workqueue: rtl83xx otto_l3_fib_event_work_do

otto_table_index_ok() refuses the access, so the write silently does not
happen on every occurrence, while the warning is a WARN_ONCE shared by
every table access in the driver and prints only the first time that
check fails after boot.

Test the result before using it. The two misses log at error level, and
the prints that name the id move into the branch that has one.

Both branches are reachable on RTL930x only: route_lookup_hw(),
find_slot() and host_route_write() are set in otto_l3_930x_cfg alone,
and only under CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD, which no
target config sets. On RTL838x, RTL839x and RTL931x those ops are NULL
and the removal path is unchanged.

Functionally tested on a Hasivo S1100W-8XGT-SE (RTL9303), kernel
6.18.44, with the offload symbol set, adding a route via a gateway that
never resolves and deleting it. On pristine main a /32 warns on the host
route table (1049, 8192 rows) and a /24 on the prefix route table (1053,
512 rows); with this patch neither warns, the lookups still return -1
and the miss is reported instead of reaching the table write.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25170
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-14 21:45:54 +02:00
Max Grass 883ebad9ba qualcommax: qca_ppe: trap slow-protocol frames to the CPU
ppe_ctrlpkt_init() redirects only the STP address 01:80:c2:00:00:00
(RFDB entry 31, APP_CTRL[0]) to the CPU port. The slow-protocols
address 01:80:c2:00:00:02 has no entry, so LACPDUs sent by a switch
never reach a Linux bond on the LAN ports: the bond keeps
"Partner Mac Address: 00:00:00:00:00:00" and every 802.3ad group stays
unformed, while the switch side reports the board's own LACPDUs.

Add RFDB entry 30 for 01:80:c2:00:00:02 and let APP_CTRL[0] match
entries 30 and 31 (bits 32 and 33 of the RFDB index bitmap; the
field layout follows the SSDK hppe_ctrlpkt_reg.h / hppe_fdb_reg.h).

Tested on a Xiaomi AX3600 against a switch running LACP: lan1+lan2 in
an 802.3ad bond converge (both slaves in one aggregator, partner MAC
set, port state 0x3f on both ends) and carry ~1.3 Gbit/s per direction
over the two 1 GbE links with 8 parallel flows. Before the change the
same setup never negotiated.

Signed-off-by: Max Grass <gh-owrt-1@maxgrass.eu>
Link: https://github.com/openwrt/openwrt/pull/25184
Signed-off-by: Robert Marko <robimarko@gmail.com>
2026-09-14 20:42:45 +02:00
Gennaro Cimmino ad7179f9b9 realtek: l3: rtl930x: dump the L3 route tables in debugfs
Debugging the L3 offload means knowing what the silicon actually holds,
and nothing in the driver exposes it. The route model lives in the
hardware tables, and the HIT bit that says whether an entry was ever
used exists only there: it has no clear-on-read and no clear register,
so the driver's own view cannot answer either question.

Add realtek_otto_l3/routes, a read-only sweep of both RTL9300 route
tables, named after the realtek_otto_serdes tree in
mdio-realtek-otto-serdes.c. It walks the raw address space rather than
the driver's own list, because with the offload symbol off the driver's
table is empty while the silicon may not be, and it decodes each entry
against the field positions used by otto_l3_930x_host_route_write() and
otto_l3_930x_route_write() in this file. Both sweeps take their bound
from otto_table_rows(), so the row count of a table stays in the table
driver alone. The host table holds six entries in every eight
addresses, so the two unused slots of each bucket are skipped.

Add realtek_otto_l3/clear_route_hits next to it. Writing to it clears
the HIT bit of every unicast entry by rewriting the entry, which is what
the vendor SDK does on RTK_L3_FLAG_HIT_CLEAR; it is a separate
write-only file so that reading the table stays free of side effects,
and one write runs one sweep. Like the dump, it walks the table by the
width of each entry, because the trailing slots of a wider one hold
address bits that would read as a valid entry and be written back over
the real one. Multicast entries are left alone and their number is
reported, rather than being silently skipped, and a table that cannot
be taken is reported to the writer instead of looking like success.

The files are created from a .dbgfs_init hook in struct otto_l3_config,
so the dump follows the compatible match table like every other
family-specific operation and no family test is needed. Only the RTL9300
configuration sets the hook, and only when
CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD is on, which no target config
does. With the symbol off nothing references the dump and the compiler
drops it: l3.o then carries 40 bytes more than main, the extra
pointer in each of the four configuration tables and the NULL test in
the probe, and none of the dump itself.

Functionally tested on a Hasivo S1100W-8XGT-SE (RTL9303, RTL8264B PHYs),
kernel 6.18.44, with the symbol set. Two SVIs on separate VLANs: the
dump lists their host route entries, and a static route via a resolved
gateway appears in the prefix table as 10.99.0.0/24 with a nexthop id
and disappears when the route is deleted. Clearing and re-reading in one
command shows HIT back to 0, and it returns to 1 on the next packet, so
the file reports the live state of the hardware rather than a cached
copy.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25167
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-09-14 17:41:34 +02:00