feat(fpga): Auto-detect CB FPGA BDF at source time

blanton_fpga_pcimem.sh V1.5.0.

The four FUNCT0..3_RES sysfs paths were hard-coded and had to be
edited for every DUT, because the CB FPGA's BDF changes with the
PCIe enumeration (0000:03:00.x / 0000:05:00.x seen so far).

Detection order at source time: FPGA_BDF override -> sysfs scan for
vendor 0x1590 with all four functions exposing resource0 -> lspci
-Dnn name/id match -> FPGA_BDF_FALLBACK. Adds fpga_rescan for a
DUT swap, FPGA_BDF / FPGA_VENDOR_ID / FPGA_LSPCI_MATCH overrides,
FPGA_BDF_ACTIVE reporting and FPGA_QUIET. Detection runs once, so
cb_fpga / pmc / icb / swb keep zero per-command overhead.
This commit is contained in:
2026-08-17 16:32:42 +08:00
parent 725f51681a
commit 9bf4291d17
@@ -17,10 +17,21 @@
# V1.4.2 2026-08-10 Change: FUNCT0..3_RES BDF updated 0000:04:00.x -> 0000:03:00.x (current unit's enumeration). # V1.4.2 2026-08-10 Change: FUNCT0..3_RES BDF updated 0000:04:00.x -> 0000:03:00.x (current unit's enumeration).
# V1.4.3 2026-08-12 Change: FUNCT0..3_RES BDF updated 0000:03:00.x -> 0000:05:00.x (current unit's enumeration). # V1.4.3 2026-08-12 Change: FUNCT0..3_RES BDF updated 0000:03:00.x -> 0000:05:00.x (current unit's enumeration).
# V1.4.4 2026-08-12 Change: FUNCT0..3_RES BDF back to 0000:03:00.x for the DUT on COM36. # V1.4.4 2026-08-12 Change: FUNCT0..3_RES BDF back to 0000:03:00.x for the DUT on COM36.
# NOTE: this BDF is per-unit. Check with # V1.5.0 2026-08-17 Change: BDF is no longer hard-coded. FUNCT0..3_RES are now
# lspci -Dnn | grep -i fpga or # auto-detected at source time by scanning sysfs for the HPE
# ls -d /sys/bus/pci/devices/0000:*:00.3 # vendor id (0x1590) with all four functions .0-.3 present,
# and edit the four lines below if it differs. # falling back to `lspci -Dnn` name/id match, then to
# FPGA_BDF_FALLBACK. No more editing this file per DUT.
# Add: fpga_rescan (re-detect after DUT swap / re-enumeration),
# FPGA_BDF / FPGA_VENDOR_ID / FPGA_LSPCI_MATCH overrides,
# FPGA_BDF_ACTIVE reporting the BDF in use.
# Note: detection runs ONCE at source time (one INFO line on
# stdout, WARN/FAIL on stderr). FPGA_QUIET=1 silences the
# INFO line. cb_fpga/pmc/icb/swb never re-scan, so there is
# no per-command output and no per-command overhead.
# NOTE: the old per-unit NOTE ("edit the four lines below")
# no longer applies - detection handles it. To pin a BDF
# manually: FPGA_BDF=0000:05:00 fpga_rescan
# ============================================================================= # =============================================================================
# #
# SONiC hardware has no memtool / devmem, but it has pcimem. pcimem mmaps the PCI # SONiC hardware has no memtool / devmem, but it has pcimem. pcimem mmaps the PCI
@@ -42,26 +53,112 @@
# icb_fpga <addr> [data] # icb_fpga <addr> [data]
# swb0_fpga <addr> [data] # swb0_fpga <addr> [data]
# swb1_fpga <addr> [data] # swb1_fpga <addr> [data]
# fpga_rescan re-detect the CB FPGA BDF (after a DUT swap)
# #
# data present = write, absent = read. # data present = write, absent = read.
# Usage: source blanton_fpga_pcimem.sh # Usage: source blanton_fpga_pcimem.sh
# === CB FPGA PCIe resource file (sysfs) === # === CB FPGA PCIe resource file (sysfs) - AUTO-DETECTED ===
# Use lspci -D to find the BDF (domain:bus:dev.fn); resource0 is the sysfs mapping of BAR0. # The CB FPGA's BDF (domain:bus:dev.fn) changes per unit / per enumeration, so it is
# e.g. lspci -Dnn | grep -i fpga -> 0000:02:00.0 ... # detected at source time instead of being hard-coded. resource0 is the sysfs mapping
# memtool variant fills in the BAR value; pcimem variant fills in the resource file # of BAR0. (memtool variant fills in the BAR value; pcimem variant fills in the
# path instead (offset becomes relative to BAR). # resource file path instead, so offsets become relative to BAR.)
FUNCT0_RES=/sys/bus/pci/devices/0000:03:00.0/resource0 #
FUNCT1_RES=/sys/bus/pci/devices/0000:03:00.1/resource0 # Detection order:
FUNCT2_RES=/sys/bus/pci/devices/0000:03:00.2/resource0 # 1. FPGA_BDF override e.g. FPGA_BDF=0000:05:00 (domain:bus:dev, WITHOUT .fn)
FUNCT3_RES=/sys/bus/pci/devices/0000:03:00.3/resource0 # 2. sysfs vendor scan /sys/bus/pci/devices/*.0 whose vendor == FPGA_VENDOR_ID
# (0x1590 = Hewlett Packard Enterprise) and that has all
# four functions .0 .1 .2 .3 exposing resource0
# 3. lspci -Dnn fallback lines matching FPGA_LSPCI_MATCH
# ("Hewlett Packard Enterprise" or vendor id "[1590:")
# 4. FPGA_BDF_FALLBACK last-known BDF, only if 1-3 all fail
#
# Overrides (export before sourcing, or set and call fpga_rescan afterwards):
# FPGA_BDF=0000:05:00 pin a specific device, skip detection
# FPGA_VENDOR_ID=0x10ee different vendor (e.g. a Xilinx-branded board)
# FPGA_LSPCI_MATCH='...' custom lspci grep -iE pattern
FPGA_VENDOR_ID="${FPGA_VENDOR_ID:-0x1590}"
FPGA_LSPCI_MATCH="${FPGA_LSPCI_MATCH:-Hewlett Packard Enterprise|\[1590:}"
FPGA_BDF_FALLBACK="${FPGA_BDF_FALLBACK:-0000:03:00}"
# Auto-detect example (uncomment to use; needs the FPGA's BDF prefix): # True if all four functions of <bdf> exist and expose resource0.
# _BDF=0000:02:00 # Usage: _fpga_bdf_ok <domain:bus:dev>
# FUNCT0_RES=/sys/bus/pci/devices/${_BDF}.0/resource0 _fpga_bdf_ok() {
# FUNCT1_RES=/sys/bus/pci/devices/${_BDF}.1/resource0 local bdf="$1" fn
# FUNCT2_RES=/sys/bus/pci/devices/${_BDF}.2/resource0 for fn in 0 1 2 3; do
# FUNCT3_RES=/sys/bus/pci/devices/${_BDF}.3/resource0 [ -e "/sys/bus/pci/devices/${bdf}.${fn}/resource0" ] || return 1
done
return 0
}
# Print the detected FPGA BDF prefix (domain:bus:dev) on stdout; non-zero if none.
_fpga_detect_bdf() {
local cands="" bdf dir vend want
# 1. explicit override wins (tolerate a trailing ".fn" being included)
if [ -n "${FPGA_BDF:-}" ]; then
bdf="$FPGA_BDF"
case "$bdf" in *.[0-7]) bdf="${bdf%.*}" ;; esac
echo "$bdf"
return 0
fi
want=$(echo "$FPGA_VENDOR_ID" | tr 'A-Z' 'a-z')
# 2. sysfs vendor-ID scan (no lspci / pci.ids needed)
for dir in /sys/bus/pci/devices/*:*.0; do
[ -e "$dir/vendor" ] || continue
vend=$(tr 'A-Z' 'a-z' < "$dir/vendor" 2>/dev/null)
[ "$vend" = "$want" ] || continue
bdf="${dir##*/}"; bdf="${bdf%.0}"
_fpga_bdf_ok "$bdf" && cands="$cands $bdf"
done
# 3. lspci fallback (device name match, in case the vendor id differs)
if [ -z "$cands" ] && command -v lspci >/dev/null 2>&1; then
for bdf in $(lspci -Dnn 2>/dev/null | grep -iE "$FPGA_LSPCI_MATCH" \
| awk '{print $1}' | sed 's/\.[0-9a-f]*$//' | sort -u); do
_fpga_bdf_ok "$bdf" && cands="$cands $bdf"
done
fi
set -- $cands
[ $# -eq 0 ] && return 1
if [ $# -gt 1 ]; then
echo -e "[\033[33mWARN\033[0m] multiple candidate FPGAs found:$cands -> using $1" >&2
echo -e " set FPGA_BDF=<domain:bus:dev> and run fpga_rescan to pick another." >&2
fi
echo "$1"
}
# (Re)detect the FPGA BDF and refresh FUNCT0..3_RES. Called once at source time;
# call again by hand after swapping/re-enumerating a DUT.
# The one-line INFO goes to STDOUT (so wrappers that already do
# `source ... >/dev/null` stay silent); WARN/FAIL go to STDERR.
# Set FPGA_QUIET=1 to suppress the INFO line entirely.
fpga_rescan() {
local bdf
bdf=$(_fpga_detect_bdf)
if [ -z "$bdf" ]; then
bdf="$FPGA_BDF_FALLBACK"
echo -e "[\033[33mWARN\033[0m] no FPGA found (vendor $FPGA_VENDOR_ID / '$FPGA_LSPCI_MATCH');" >&2
echo -e " falling back to $bdf. Check with: lspci -Dnn | grep -iE 'Hewlett|fpga'" >&2
fi
FPGA_BDF_ACTIVE="$bdf"
FUNCT0_RES=/sys/bus/pci/devices/${bdf}.0/resource0
FUNCT1_RES=/sys/bus/pci/devices/${bdf}.1/resource0
FUNCT2_RES=/sys/bus/pci/devices/${bdf}.2/resource0
FUNCT3_RES=/sys/bus/pci/devices/${bdf}.3/resource0
if _fpga_bdf_ok "$bdf"; then
[ "${FPGA_QUIET:-0}" = "1" ] || \
echo -e "[\033[34mINFO\033[0m] CB FPGA BDF = \033[36m${bdf}.0-.3\033[0m (resource0)"
else
echo -e "[\033[31mFAIL\033[0m] ${bdf}.0-.3 resource0 not all present - register access will fail." >&2
return 1
fi
}
fpga_rescan
# === VSPI window base offset (relative to CB Function 2 resource0 start) === # === VSPI window base offset (relative to CB Function 2 resource0 start) ===
# NOTE: CB.F2 has TWO near-identical VSPI register blocks (see spec register map): # NOTE: CB.F2 has TWO near-identical VSPI register blocks (see spec register map):
@@ -268,6 +365,9 @@ blanton_fpga_help() {
echo -e " \033[33mswb0_fpga\033[0m <addr> [data] SWB0 FPGA via VSPI" echo -e " \033[33mswb0_fpga\033[0m <addr> [data] SWB0 FPGA via VSPI"
echo -e " \033[33mswb1_fpga\033[0m <addr> [data] SWB1 FPGA via VSPI" echo -e " \033[33mswb1_fpga\033[0m <addr> [data] SWB1 FPGA via VSPI"
echo -e " \033[33mfpga_debug\033[0m on|off Toggle debug mode (print commands and execute)" echo -e " \033[33mfpga_debug\033[0m on|off Toggle debug mode (print commands and execute)"
echo -e " \033[33mfpga_rescan\033[0m Re-detect CB FPGA BDF (after DUT swap / re-enum)"
echo ""
echo -e " Active CB FPGA BDF: \033[36m${FPGA_BDF_ACTIVE:-unknown}\033[0m .0-.3 (pin with: FPGA_BDF=0000:05:00 fpga_rescan)"
echo "" echo ""
echo -e " Omit [data] to \033[32mread\033[0m, provide [data] to \033[31mwrite\033[0m." echo -e " Omit [data] to \033[32mread\033[0m, provide [data] to \033[31mwrite\033[0m."
echo -e " Backend: \033[36mpcimem\033[0m (sysfs resource file + relative offset)." echo -e " Backend: \033[36mpcimem\033[0m (sysfs resource file + relative offset)."