Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
41c8c47
utils: kernel-refresh.sh: only run upgrade steps on a version change
troglobit Oct 7, 2026
6f42850
board: tactical-1000: seed uboot.env when provisioning
troglobit Oct 7, 2026
df11748
configs: add missing boards to aarch64_minimal_defconfig
troglobit Oct 7, 2026
bd4150e
rootfs: make log and follow available in BusyBox ash
troglobit Oct 7, 2026
7557338
package: add symreg, Microchip switch register access by name
troglobit Oct 7, 2026
729f405
board: lan969x: add README with symreg debug notes
troglobit Oct 7, 2026
4ae478e
doc: ChangeLog for the Laguna fixes and the symreg tool
troglobit Oct 8, 2026
cc5d536
confd: ptp: allow 100 ms for hardware transmit timestamps
troglobit Oct 8, 2026
31b2708
confd: ptp: raise the 802.1AS link delay threshold, make it configurable
troglobit Oct 12, 2026
6c39b47
linux: sparx5: fix multicast to the CPU on standalone ports
troglobit Oct 12, 2026
f42c0a7
linux: sparx5: fix bridge IP address reachability on Laguna
troglobit Oct 12, 2026
aec6332
linux: sparx5: fix link aggregates losing their MAC entry on Laguna
troglobit Oct 12, 2026
9f2d590
rootfs: give ports a chassis-derived address on every board without one
troglobit Oct 12, 2026
4576246
probe: read the product VPD from vpd.onie on the aux partition
troglobit Oct 12, 2026
b39c079
confd: restore a chassis-derived port address when there is no perman…
troglobit Oct 12, 2026
e948c51
board: tactical-1000: offer to write the VPD file when provisioning
troglobit Oct 12, 2026
b37a019
linux: micrel: recognize the LAN8804, a LAN8814 without the 1588 unit
troglobit Oct 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions board/aarch64/microchip-ev23x71a/Config.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
config BR2_PACKAGE_MICROCHIP_EV23X71A
bool "Microchip EV23X71A (Laguna)"
depends on BR2_aarch64
select BR2_PACKAGE_SYMREG
help
Support for the Microchip EV23X71A evaluation board, based on
the LAN969x (Laguna) family of TSN capable switches. 24 GbE
Expand Down
12 changes: 12 additions & 0 deletions board/aarch64/microchip-ev23x71a/dts/microchip/infix.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@
};
};
};

/* Register access by name for the symreg tool, debugfs only */
&axi {
symreg@e00c0000 {
compatible = "microchip,sparx5-symreg";
reg = <0xe00c0000 0x10000>,
<0xe2000000 0x2000000>;
reg-names = "cpu", "dev";
microchip,symreg = <0xe00c0000 0x10000>,
<0xe2000000 0x2000000>;
};
};
72 changes: 72 additions & 0 deletions board/aarch64/microchip-lan969x/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Microchip LAN969x (Laguna)

Files shared by the boards built on the LAN969x switch family:

| Board | Package |
|-------------------------------------------------|------------------------------------|
| [Microchip EV23X71A](../microchip-ev23x71a) | `BR2_PACKAGE_MICROCHIP_EV23X71A` |
| [Novarq Tactical 1000](../novarq-tactical-1000) | `BR2_PACKAGE_NOVARQ_TACTICAL_1000` |

`uboot/` holds the U-Boot config fragment and environment used by the
`*_boot_defconfig` of each board. Kernel device tree and configuration
fixups stay with each board, see its `dts/` directory and `.mk` file.

A new Laguna board should select `BR2_PACKAGE_SYMREG` in its `Config.in`
and carry the `microchip,sparx5-symreg` node in its `dts/microchip/infix.dtsi`,
copied from one of the boards above, so the tool below works on it too.

## Debugging

### Register access by name

Every Laguna board ships `symreg`, Microchip's tool for reading and
writing switch registers by their datasheet names. It talks to the
`symreg` debugfs driver, which maps the register space the device tree
node describes and exposes it as `/sys/kernel/debug/symreg/mem`. Root
only, since debugfs is.

```
symreg --help # options and the register syntax
symreg -m # MAC table
symreg -v # VLAN table
symreg -c 0 # VCAP instance 0
symreg -s # stream table

symreg 'DEV2G5[29]*' # all registers of port 29's device block
symreg 'ASM*[29]*' # ingress side of the same port
symreg -a 'DSM*[29]*' # same, with the physical addresses

symreg REG[idx] # read one register
symreg REG[idx].FIELD # read one field
symreg REG[idx].FIELD 1 # write one field, add -f for wildcards
```

Register and field names follow the LAN969x datasheet. Quote the
wildcards or the shell expands them. The dispatcher `symreg` picks the
SoC from `/proc/device-tree/compatible` and runs `symreg_lan969x`, which
can also be called directly.

The tool reads live hardware, so the useful pattern for an intermittent
fault is a snapshot while the port works, another once it has failed,
and a diff of the two. For the management port, which is switch port 29
on both boards:

```bash
for blk in 'DEV2G5[29]*' 'ASM*[29]*' 'DSM*[29]*' 'QSYS*[29]*'; do
symreg "$blk"
done >/tmp/port29-$(date +%s).txt
```

Check the PHY as well. The management PHY sits on the GCB MDIO bus and
shares one level triggered interrupt line with the copper PHYs, so a
stale link state can come from a missed PHY interrupt as well as from
the switch. Read it with `mdio` from mdio-tools, see the
[EV23X71A README](../microchip-ev23x71a/README.md#debug-and-analysis),
which also covers the VCAP debugfs and `ethtool` counters; both apply to
either board.

### Writing registers

Writes take effect immediately and bypass the driver, which keeps no
record of them. Expect the driver's own view to disagree afterwards,
and reboot before trusting any behaviour again.
1 change: 1 addition & 0 deletions board/aarch64/novarq-tactical-1000/Config.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
config BR2_PACKAGE_NOVARQ_TACTICAL_1000
bool "Novarq Tactical 1000 (Laguna)"
depends on BR2_aarch64
select BR2_PACKAGE_SYMREG
help
Support for the Novarq Tactical 1000, based on the LAN969x
(Laguna) family of TSN capable switches. 24 GbE copper ports,
Expand Down
18 changes: 18 additions & 0 deletions board/aarch64/novarq-tactical-1000/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,23 @@ Storage][7]. A unit still on the vendor U-Boot netboots as described in
[Netboot with a Vendor U-Boot][8]. The first boot grows `var` to fill the
eMMC and reboots once by itself.

## Identity

The board has no MAC address in OTP, so without help every boot gets a
random base MAC and random port addresses, which also change the
link-local addresses the test rig finds the unit by. `provision-tactical`
offers to write a base MAC and a serial number to `vpd.onie` on the `aux`
partition, which the system reads as its product VPD. On a unit already
provisioned, write it by hand and reboot:

```bash
echo '{"mac-address":"02:00:00:7a:c7:00","serial-number":"tact1","vendor":"Novarq","product-name":"Tactical-1000"}' \
| onieprom -e | sudo tee /mnt/aux/vpd.onie >/dev/null
```

The base MAC becomes the chassis address, `e1` gets base + 1, `e2` base + 2,
and so on, `mgmt` after the last `e` port. See [VPD][9] for the format.

## Device Tree

Cherry-picked from [Novarq's kernel tree][2]. One commit adapts it to
Expand Down Expand Up @@ -152,3 +169,4 @@ unused.
[6]: https://github.com/novarq/tactical-1000/blob/main/docs/boot-modes.md
[7]: ../../../doc/netboot.md#installing-to-onboard-storage
[8]: ../../../doc/netboot.md#netboot-with-a-vendor-u-boot
[9]: ../../../doc/vpd.md#factory-partition-or-file
12 changes: 12 additions & 0 deletions board/aarch64/novarq-tactical-1000/dts/microchip/infix.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@
};
};
};

/* Register access by name for the symreg tool, debugfs only */
&axi {
symreg@e00c0000 {
compatible = "microchip,sparx5-symreg";
reg = <0xe00c0000 0x10000>,
<0xe2000000 0x2000000>;
reg-names = "cpu", "dev";
microchip,symreg = <0xe00c0000 0x10000>,
<0xe2000000 0x2000000>;
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,24 @@ if ask "Create aux, primary ${imgsize}, secondary ${imgsize}, cfg ${cfgsize}, an
mkfs.ext4 -qF -L aux -m 0 -i 4096 -O ^metadata_csum,^metadata_csum_seed,uninit_bg "${disk}p4"
mkfs.ext4 -qF -L cfg -m 0 -i 4096 -O uninit_bg "${disk}p7"
mkfs.ext4 -qF -L var -m 0 -i 4096 -O uninit_bg "${disk}p8"
#
# RAUC tracks slot boot state in uboot.env, seed it as prod/provision does.
mnt=$(mktemp -d)
mount -t ext4 "${disk}p4" "$mnt"
echo 1 >"$mnt"/resized
mkenvimage -s 0x4000 -o "$mnt"/uboot.env - <<EOF
BOOT_ORDER=primary secondary net
BOOT_primary_LEFT=1
BOOT_secondary_LEFT=1
BOOT_net_LEFT=1
EOF
# No MAC address in OTP, the probe takes the identity from this file
if ask "Give the unit an identity in vpd.onie on aux, a base MAC address and a serial number?"; then
printf "Base MAC address: "; read -r mac
printf "Serial number: "; read -r serial
printf '{"mac-address":"%s","serial-number":"%s","vendor":"Novarq","product-name":"Tactical-1000"}' \
"$mac" "$serial" | onieprom -e >"$mnt"/vpd.onie
fi
umount "$mnt"
rmdir "$mnt"
fi
Expand Down
16 changes: 1 addition & 15 deletions board/common/rootfs/etc/bash.bashrc
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,7 @@ bind "set show-all-if-ambiguous on"

export LANG=C.UTF-8

log()
{
local fn="/var/log/syslog"
[ -n "$1" ] && fn="/var/log/$1"
less +G -r "$fn"
}

follow ()
{
local fn="/var/log/syslog"
[ -n "$1" ] && fn="/var/log/$1"

tail -F -n +1 "$fn"
}

# log and follow are defined in /etc/profile.d/log.sh
_logfile_completions()
{
local cur=${COMP_WORDS[COMP_CWORD]}
Expand Down
15 changes: 15 additions & 0 deletions board/common/rootfs/etc/profile.d/log.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Page or follow a log file, default syslog. Plain sh, so BusyBox ash
# and bash both get it; the bash completions live in /etc/bash.bashrc.
log()
{
local fn="/var/log/syslog"
[ -n "$1" ] && fn="/var/log/$1"
less +G -r "$fn"
}

follow()
{
local fn="/var/log/syslog"
[ -n "$1" ] && fn="/var/log/$1"
tail -F -n +1 "$fn"
}
22 changes: 13 additions & 9 deletions board/common/rootfs/usr/libexec/infix/init.d/00-probe
Original file line number Diff line number Diff line change
Expand Up @@ -481,20 +481,22 @@ def probe_dmisystem(out):


FACTORY_PART = "/dev/disk/by-partlabel/factory"
AUX_VPD = "/mnt/aux/vpd.onie"


def factory_partition_vpd():
"""Product VPD from an ONIE TLV at the start of the factory partition.
def file_vpd(path):
"""Product VPD from an ONIE TLV in a file, or at the start of a partition.

Boards without a VPD EEPROM, e.g. SBCs, can be given an identity by
writing a TLV to a partition labelled "factory". Anyone with write
access to the disk can change it, so it is never trusted.
writing a TLV to a partition labelled "factory", or to vpd.onie on
the aux partition. Anyone with write access to the disk can change
it, so it is never trusted.
"""
if not os.path.exists(FACTORY_PART):
if not os.path.exists(path):
return None

try:
with open(FACTORY_PART, "rb", 0) as f:
with open(path, "rb", 0) as f:
data = onieprom.from_tlv(f)
except Exception: # pylint: disable=broad-except
return None
Expand All @@ -516,9 +518,11 @@ def probe_dtsystem(out):
vpds = dtsys.infix_vpds()

if not any(vpd["board"] == "product" and vpd["available"] for vpd in vpds):
vpd = factory_partition_vpd()
if vpd:
vpds.append(vpd)
for path in (FACTORY_PART, AUX_VPD):
vpd = file_vpd(path)
if vpd:
vpds.append(vpd)
break

model = dtsys.base.str("model")
if model:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
#!/usr/bin/env python3
"""Give ports without a hardware MAC address a chassis-derived one.

The BPI-R3 family has no MAC EEPROM, so every port boots with a random
address, and the switch ports inherit that from their conduit. When
the product VPD provides a base MAC, hand each such port a stable
address derived from it: base + 1, base + 2, ... in interface name
order. This mirrors what products with real hardware addresses get
from their device tree. Ports with a permanent address are left alone.

Runs from /etc/product/init.d, before the DSA conduit is renamed, so
it sorts as eth0 and takes base + 1.
Boards without a MAC EEPROM or OTP boot with a random address on every
port. When the product VPD provides a base MAC, hand each such port a
stable address derived from it: base + 1, base + 2, ... in interface
name order, with numbers compared as numbers so e2 comes before e10.
This mirrors what products with real hardware addresses get from their
device tree. Ports with a permanent address are left alone.

Runs from /etc/product/init.d on the boards that need it, before a DSA
conduit is renamed, so it sorts as eth0 and takes base + 1.

With an interface name as argument, prints the address that port gets
and sets nothing, for confd to restore a port's default address.
"""
import json
import os
import re
import subprocess
import sys

Expand Down Expand Up @@ -48,9 +52,13 @@ def read(path):
return f.read().strip()


def natural(name):
return [int(s) if s.isdigit() else s for s in re.split(r"(\d+)", name)]


def ports():
"""Wired ports whose address the kernel did not get from hardware."""
for name in sorted(os.listdir(NET)):
for name in sorted(os.listdir(NET), key=natural):
path = os.path.join(NET, name)
if not os.path.exists(os.path.join(path, "device")):
continue
Expand All @@ -66,20 +74,28 @@ def ports():


def main():
query = sys.argv[1] if len(sys.argv) > 1 else None

base = vpd_base_mac()
if not base:
return 0
return 1 if query else 0

for offset, name in enumerate(ports(), start=1):
mac = mac_add(base, offset)
if query:
if name == query:
print(mac)
return 0
continue

rc = subprocess.run(["ip", "link", "set", "dev", name, "address", mac],
check=False)
if rc.returncode:
log(f"failed setting {name} address {mac}")
continue
log(f"{name}: {mac} (chassis + {offset})")

return 0
return 1 if query else 0


if __name__ == "__main__":
Expand Down
3 changes: 3 additions & 0 deletions configs/aarch64_minimal_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,16 @@ BR2_PACKAGE_HOST_GENEXT2FS=y
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
BR2_PACKAGE_HOST_UBOOT_TOOLS_FDT_ADD_PUBKEY=y
BR2_PACKAGE_ACER_CONNECT_VERO_W6M=y
BR2_PACKAGE_ALDER_ALDER=y
BR2_PACKAGE_BANANAPI_BPI_R3=y
BR2_PACKAGE_BANANAPI_BPI_R4=y
BR2_PACKAGE_BANANAPI_BPI_R64=y
BR2_PACKAGE_FRIENDLYARM_NANOPI_R2S=y
BR2_PACKAGE_MARVELL_CN9130_CRB=y
BR2_PACKAGE_MARVELL_ESPRESSOBIN=y
BR2_PACKAGE_MICROCHIP_EV23X71A=y
BR2_PACKAGE_NOVARQ_TACTICAL_1000=y
BR2_PACKAGE_RASPBERRYPI_RPI64=y
BR2_PACKAGE_STYX_DCP_SC_28P=y
IX_VENDOR_HOME="https://www.kernelkit.org"
Expand Down
Loading
Loading