From dd558a7b0f4efcb2890515b60bdccf5e105863b9 Mon Sep 17 00:00:00 2001 From: ETWen Date: Tue, 15 Sep 2026 21:27:25 +0800 Subject: [PATCH] feat(dsc): Add the 100G link down/up cycle test bcm_100g_dsc_cycle.sh tunes once - gbsyncd paused, serdes-tx-set on sys 0..7, tx_taps per lane - then repeats: port 268 en=0, wait, en=1, wait, phydiag 268 dsc on both units, and the retimer read back with serdes-tx-get / serdes-rx-get for sys 0..7. One log per run under ~/dsc_log, split by "### TEST CYCLE n/N", ending in "### DSC_CYCLE_DONE rc=" for a TTL wait to key on. Waiting for a link state polls "bcmcmd ps " rather than reading "show interfaces status". "port en=" changes the SDK, and the SONiC table only follows once gbsyncd and orchagent have synced it - and this test pauses gbsyncd, so the SONiC table was the wrong thing to wait on. The state is read from the row whose first field ends in "()", and "down" is tested as "not up" so !ena counts. All output is ASCII English on purpose: the DUT serial console mangles UTF-8, and a Chinese error message came back as "ERROR: -c ? 1" - an error you cannot read is worse than none. -d echoes every command as a grey [CMD] line, CMD_DELAY paces them, and -n is a dry run that touches nothing and sleeps not at all. The cycle count may be given as a bare argument, which is what people type first. Not verified on hardware. gbsyncd is unpaused again on exit, Ctrl-C included. tools/100G_dsc_cycle.txt is the hand-typed bench version of the same commands, kept the way BER_Test.txt and TR518.txt are, so the script can be checked against what a person would actually run. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_014RetWKFZFG1ZHcitQAyhwM --- .../Blanton_Script/bcm_100g_dsc_cycle.sh | 608 ++++++++++++++++++ tools/100G_dsc_cycle.txt | 90 +++ 2 files changed, 698 insertions(+) create mode 100644 src/Script_ABC_Blanton/Blanton_Script/bcm_100g_dsc_cycle.sh create mode 100644 tools/100G_dsc_cycle.txt diff --git a/src/Script_ABC_Blanton/Blanton_Script/bcm_100g_dsc_cycle.sh b/src/Script_ABC_Blanton/Blanton_Script/bcm_100g_dsc_cycle.sh new file mode 100644 index 0000000..f45b4b6 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/bcm_100g_dsc_cycle.sh @@ -0,0 +1,608 @@ +#!/bin/sh +# ============================================================================= +# bcm_100g_dsc_cycle.sh +# +# Author : ETWen +# Date : 20260909 +# +# Version History +# V1.0.0 20260909 Initial Version +# V1.1.0 20260909 All runtime output is ASCII English - the DUT serial +# console mangles UTF-8 (a Chinese error message came +# back as "ERROR: -c ? 1"). Cycle count may be given as +# a bare argument. Added -d to echo every command, and +# CMD_DELAY to pace them. +# V1.2.0 20260909 Wait on "bcmcmd ps " instead of +# "show interfaces status". The state comes from the +# SDK, which is what "port en=" actually changes, so it +# no longer depends on gbsyncd syncing into the DB. +# +# Description: +# Link down/up cycling on the 100G uplink. After every re-link it collects a +# SerDes DSC dump and reads the retimer back, so you can see whether the +# tuned TX taps settle to the same place each time the link comes up. +# +# One run has two parts: +# 1. Tuning -- once. pause gbsyncd -> serdes-tx-set sys 0..7 +# -> tx_taps set on four lanes of each unit +# 2. Cycle -- repeated N times: +# port en=0 -> wait until "ps " reads !ena on both units +# port en=1 -> wait until "ps " reads up on both units +# phydiag dsc on each unit +# serdes-tx-get / serdes-rx-get sys 0..7 +# all of it appended to one log, under a per-cycle heading +# +# Command source: tools/100G_dsc_cycle.txt (the hand-typed bench version). +# Change that file and this one together. +# +# Deployment: +# Script : /root/Blanton_Script/bcm_100g_dsc_cycle.sh +# Log : ~/dsc_log/100G_dsc_cycle_test_.log +# One file per run, every cycle in it, split by "### TEST CYCLE n/N". +# +# Paths come from $HOME. Run as root (after sudo -i) and ~ is /root. +# +# Usage: +# ./bcm_100g_dsc_cycle.sh # print this help +# ./bcm_100g_dsc_cycle.sh 200 # 200 cycles +# ./bcm_100g_dsc_cycle.sh -c 200 # same thing +# ./bcm_100g_dsc_cycle.sh -c 200 -d # echo every command as it is issued +# ./bcm_100g_dsc_cycle.sh -c 10 -T # skip tuning, cycle only +# ./bcm_100g_dsc_cycle.sh -c 1 -n # dry run, print commands, touch nothing +# +# Exit code: +# 0 = every cycle linked down and up as expected, and all data was collected +# 1 = a cycle timed out waiting for link, or data was missing +# 2 = bad argument / path +# 3 = a required tool is missing (bcmcmd / show / blanton_barchetta_tool) +# +# The last line is always "### DSC_CYCLE_DONE rc=", for a TTL wait to +# key on. +# +# Design notes: +# - POSIX sh. No bash, no Python. +# - All runtime output is plain ASCII. The DUT console is not UTF-8 clean: +# Chinese comes back as "M-^A"-style garbage, and an error you cannot read +# is worse than no error at all. Comments are English for the same reason - +# whoever debugs this on the bench is reading it through that console. +# - Link state comes from "bcmcmd -n -c 'ps '". Its header is +# two stacked lines, so a column index cannot be derived from it the way +# it can from a SONiC table. Instead the data row is found by its first +# field ending in "()" - e.g. ce0(268) - and the state is the field +# after it: +# ce0(268) !ena 4 100G FD ... <- port disabled +# ce0(268) up 4 100G FD ... <- link up +# "down" is therefore tested as "not up", which covers !ena as well as an +# enabled port whose link has not come back. +# - Asking the SDK rather than "show interfaces status" matters here: "port +# en=" changes the SDK, and the SONiC table only follows once gbsyncd and +# orchagent have synced it into the DB. Since this test pauses gbsyncd, +# the SONiC table was the wrong thing to wait on. +# - bcmcmd reads stdin, and inside a while loop it will swallow the loop's +# input. blanton_traffic_linespeed.sh hit this at v0.3.1 (only the first +# VLAN was configured) and bcm_dsc_scan.sh hit it again at v1.3.0 (only +# the first port was scanned). Every external command here gets +# < /dev/null. +# - bcmcmd exits 0 even when the diag shell rejects a command, so the DSC is +# verified by counting "SERDES DISPLAY DIAG DATA END", and the retimer read +# by counting sections that actually have output under them - not by exit +# code, and not by counting headings this script prints itself. +# +# Cautions: +# - !! While gbsyncd is paused the gearbox state stops being synced into the +# DB. The wait reads the SDK directly ("ps ") so it is not affected, +# but anything you check by hand with "show interfaces status" during the +# run may be stale. Set PAUSE_GBSYNCD=0 (or -P) if that gets in the way. +# - !! On exit, including Ctrl-C, both gbsyncd containers are unpaused again +# so nothing is left paused. Set RESUME_GBSYNCD=0 to keep them paused. +# - !! phydiag dsc is read-only, but port en=0/1 and tx_taps set do change +# the hardware. Do not run this at the same time as blanton_ber.sh, +# blanton_traffic_linespeed or blanton_tr518.sh - they take the same ports. +# - !! NOT verified on hardware yet. +# ============================================================================= + +set -u + +# ---------------------------------------------------------------------------- +# Knobs - change these for a different DUT or port, not the flow below +# ---------------------------------------------------------------------------- +PORT=268 # bcmcmd port number, not a port name +UNITS="0 1" # units to drive +SYS_LANES="0 1 2 3 4 5 6 7" # blanton_barchetta_tool sys lanes, tuning +SYS_TX="pre=-10 main=87 post=0" # TX setting applied to each of them + +# tx_taps, one line per lane: "
" +TX_TAPS=" +0 0 31 4 13 +0 1 31 4 13 +0 2 27 4 13 +0 3 29 4 13 +1 0 29 4 13 +1 1 30 4 13 +1 2 31 4 13 +1 3 30 4 13 +" + +TX_LANES="0 1 2 3 4 5 6 7" # retimer TX lanes read back each cycle +RX_LANES="0 1 2 3 4 5 6 7" # retimer RX lanes read back each cycle + +SUDO="" # set to "sudo" if not running as root +PAUSE_GBSYNCD=1 # pause gbsyncd0/1 before tuning +RESUME_GBSYNCD=1 # unpause again on exit, Ctrl-C included +GBSYNCD="gbsyncd0 gbsyncd1" + +LINK_WAIT=90 # give up waiting for a link state after this +POLL=2 # seconds between "ps " reads while waiting +SETTLE=2 # quiet time after link up, before collecting +CMD_DELAY=0.2 # pause after every command issued to the DUT + +OUTDIR="${HOME:-/root}/dsc_log" + +# ---------------------------------------------------------------------------- +CYCLES=0 +DRYRUN=0 +DOTUNE=1 +DEBUG=0 +RC=0 + +usage() { + cat >&2 << 'USAGE' +Usage: bcm_100g_dsc_cycle.sh [options] + bcm_100g_dsc_cycle.sh -c [options] + + -c how many cycles to run. May also be given as a bare argument. + -o log directory (default: ~/dsc_log) + -w how long to wait for a link state (default: 90) + -p how often to re-read the port state (default: 2) + -s quiet time after link up, before collecting (default: 2) + -d debug: echo every command as [CMD] before running it + -T skip tuning, go straight to the cycles + -P leave gbsyncd alone (no pause, no unpause) + -n dry run: print the commands, touch nothing + -h this help + +One log per run: + ~/dsc_log/100G_dsc_cycle_test_.log + +Each cycle is one "### TEST CYCLE n/N" section holding, in order: the "ps" +output showing the port down, the same showing it up, phydiag dsc for both +units, and the retimer serdes-tx-get / serdes-rx-get for sys 0..7. + +Waiting for a port state is a poll, not a single read: "bcmcmd ps " on +every unit, every -p seconds, until both agree or -w seconds have passed. + +Examples: + ./bcm_100g_dsc_cycle.sh 200 + ./bcm_100g_dsc_cycle.sh 200 -d + ./bcm_100g_dsc_cycle.sh -c 20 -T -w 120 +USAGE + exit 1 +} + +[ $# -eq 0 ] && usage + +# getopts stops at the first argument that is not an option, so "200 -d" would +# leave -d unread. Parse, take the bare count, then parse whatever followed it. +# getopts inside a function reads the function's own arguments; OPTIND is +# global, so it has to be reset on each entry. +PARSED=0 +parse_opts() { + OPTIND=1 + while getopts "c:o:w:p:s:dTPnh" opt; do + case "$opt" in + c) CYCLES="$OPTARG" ;; + o) OUTDIR="$OPTARG" ;; + w) LINK_WAIT="$OPTARG" ;; + p) POLL="$OPTARG" ;; + s) SETTLE="$OPTARG" ;; + d) DEBUG=1 ;; + T) DOTUNE=0 ;; + P) PAUSE_GBSYNCD=0; RESUME_GBSYNCD=0 ;; + n) DRYRUN=1 ;; + *) usage ;; + esac + done + PARSED=$((OPTIND - 1)) +} + +parse_opts "$@" +shift "$PARSED" + +# Allow the count as a bare argument: "... 200" == "... -c 200". That is what +# most people type first, and answering it with an error helps nobody. +if [ "$CYCLES" = "0" ] && [ $# -ge 1 ]; then + case "$1" in + -*) : ;; # an option; leave it for the second pass + *) CYCLES="$1"; shift ;; # anything else is meant to be the count, + esac # and the check below says so if it is not +fi + +# Anything after the count is options again: "200 -d -T" +if [ $# -gt 0 ]; then + parse_opts "$@" + shift "$PARSED" +fi + +if [ $# -gt 0 ]; then + echo "ERROR: unexpected argument '$1'" >&2 + echo " run with no argument to see the usage" >&2 + exit 2 +fi + +case "$CYCLES" in + ''|*[!0-9]*) + echo "ERROR: cycle count must be a positive integer (got: '$CYCLES')" >&2 + echo " try: $0 200 or $0 -c 200" >&2 + exit 2 ;; +esac +if [ "$CYCLES" -lt 1 ]; then + echo "ERROR: cycle count must be at least 1 (got: $CYCLES)" >&2 + exit 2 +fi + +# ---------------------------------------------------------------------------- +# Colour, only when stdout is a terminal, so a redirected run stays clean +# ---------------------------------------------------------------------------- +if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then + C_INFO=$(printf '\033[1;34m') # blue + C_OK=$(printf '\033[1;32m') # green + C_WARN=$(printf '\033[1;33m') # yellow + C_ERR=$(printf '\033[1;31m') # red + C_CMD=$(printf '\033[90m') # dark grey + C_OFF=$(printf '\033[0m') +else + C_INFO=''; C_OK=''; C_WARN=''; C_ERR=''; C_CMD=''; C_OFF='' +fi + +# A dry run touches nothing, so it must not sleep either - otherwise +# "-c 200 -n" sits there for as long as the real thing would. +naptime() { [ "$DRYRUN" = "1" ] && return 0; [ "${1:-0}" = "0" ] && return 0; sleep "$1"; } + +info() { printf '%s[info]%s %s\n' "$C_INFO" "$C_OFF" "$*"; } +ok() { printf '%s[ OK ]%s %s\n' "$C_OK" "$C_OFF" "$*"; } +warn() { printf '%s[warn]%s %s\n' "$C_WARN" "$C_OFF" "$*" >&2; } +err() { printf '%s[ERR ]%s %s\n' "$C_ERR" "$C_OFF" "$*" >&2; } + +# Both -d and -n print commands. During collection the whole block is +# redirected into a temp file, so those lines would end up in the file with +# nothing on screen. Bind fd 9 to the terminal up front and print there. +if { [ "$DEBUG" = "1" ] || [ "$DRYRUN" = "1" ]; } && ( true > /dev/tty ) 2>/dev/null; then + exec 9> /dev/tty +else + exec 9>&1 +fi +# ':' is a special built-in in dash (the DUT's /bin/sh); a failed redirection +# on one kills the whole shell with no message. Hence (true > /dev/tty) in a +# subshell above - if that cannot open, only the subshell dies. + +# Print a command the way you would type it: quote any argument that needs it, +# so the line can be copied back to the prompt as is. +# NOTE: sh has no local variables - every name assigned here is global. All +# helper variables are therefore prefixed. _show_cmd used to assign "tag", +# which silently overwrote the caller's cycle label and turned every later +# message into "[info] [CMD] : Wait Port Link Down". +_show_cmd() { + _sc_tag="$1"; _sc_col="$2"; shift 2 + { + printf '%s%s%s' "$_sc_col" "$_sc_tag" "$C_OFF" + for a in "$@"; do + case "$a" in + ''|*[!A-Za-z0-9_./=:,+-]*) printf " '%s'" "$a" ;; + *) printf ' %s' "$a" ;; + esac + done + printf '\n' + } >&9 +} + +# Every external command goes through here: never reads stdin, echoed when +# asked, and paced by CMD_DELAY so the DUT is not hammered. +run() { + [ "$DEBUG" = "1" ] && [ "$DRYRUN" = "0" ] && _show_cmd '[CMD]' "$C_CMD" "$@" + if [ "$DRYRUN" = "1" ]; then + _show_cmd ' +' "$C_CMD" "$@" + return 0 + fi + "$@" < /dev/null + _cmd_rc=$? + naptime "$CMD_DELAY" + return $_cmd_rc +} + +# Same, but discards output. Do not write "> /dev/null" at the call site or +# the [CMD] line goes with it. +runq() { + [ "$DEBUG" = "1" ] && [ "$DRYRUN" = "0" ] && _show_cmd '[CMD]' "$C_CMD" "$@" + if [ "$DRYRUN" = "1" ]; then + _show_cmd ' +' "$C_CMD" "$@" + return 0 + fi + "$@" < /dev/null > /dev/null 2>&1 + _cmd_rc=$? + naptime "$CMD_DELAY" + return $_cmd_rc +} + +# ---------------------------------------------------------------------------- +# Preflight +# ---------------------------------------------------------------------------- +if [ "$DRYRUN" = "0" ]; then + command -v bcmcmd > /dev/null 2>&1 || { err "not found: bcmcmd"; exit 3; } + # -T only skips tuning; the per-cycle retimer read still needs this tool + if [ ! -x /usr/sbin/blanton_barchetta_tool ]; then + err "not found: /usr/sbin/blanton_barchetta_tool (tuning and the per-cycle retimer read both use it)" + exit 3 + fi +fi + +# busybox sleep may not take a fraction +if [ "$DRYRUN" = "0" ] && [ "$CMD_DELAY" != "0" ] && ! sleep "$CMD_DELAY" 2>/dev/null; then + warn "sleep '$CMD_DELAY' not supported, falling back to 1" + CMD_DELAY=1 +fi + +mkdir -p "$OUTDIR" 2>/dev/null || { err "cannot create outdir: $OUTDIR"; exit 2; } +[ -w "$OUTDIR" ] || { err "outdir not writable: $OUTDIR"; exit 2; } + +TS=$(date '+%Y%m%d_%H%M%S') +LOG="${OUTDIR}/100G_dsc_cycle_test_${TS}.log" +: > "$LOG" || { err "cannot write $LOG"; exit 2; } + +STATUS_TMP=$(mktemp) || { err "mktemp failed"; exit 2; } +CYCLE_TMP=$(mktemp) || { err "mktemp failed"; exit 2; } + +# ---------------------------------------------------------------------------- +# gbsyncd must go back the way it was found, or the container stays paused +# ---------------------------------------------------------------------------- +PAUSED=0 +resume_gbsyncd() { + [ "$PAUSED" = "1" ] || return 0 + [ "$RESUME_GBSYNCD" = "1" ] || return 0 + PAUSED=0 + for _rg_c in $GBSYNCD; do + if runq $SUDO docker unpause "$_rg_c"; then + info "gbsyncd resumed: $_rg_c" + else + warn "docker unpause $_rg_c failed - check it by hand" + fi + done +} +on_exit() { rm -f "$STATUS_TMP" "$CYCLE_TMP"; resume_gbsyncd; } +on_int() { + echo "" + warn "interrupted by user" + resume_gbsyncd + printf '\n### DSC_CYCLE_DONE rc=130 (INTERRUPTED)\n' >> "$LOG" + printf '### DSC_CYCLE_DONE rc=130 (INTERRUPTED)\n' + rm -f "$STATUS_TMP" "$CYCLE_TMP" + exit 130 +} +trap on_exit EXIT +trap on_int INT TERM + +tee_log() { tee -a "$LOG"; } + +# ---------------------------------------------------------------------------- +# Link state. Find which field "Oper" is from the header row, then read that +# field on every data row. Returns 0 only when every interface matches. +# The table itself is left in $STATUS_TMP for the caller to print. +# ---------------------------------------------------------------------------- +# $1 = "up" or "down". Runs "ps " on every unit, leaves the combined +# output in $STATUS_TMP for the caller to print, and returns 0 only when every +# unit agrees. +link_is() { + _li_want="$1" + : > "$STATUS_TMP" + for _li_u in $UNITS; do + printf '\n[unit %s] bcmcmd -n %s -c "ps %s"\n' "$_li_u" "$_li_u" "$PORT" >> "$STATUS_TMP" + if [ "$DRYRUN" = "1" ]; then + _show_cmd ' +' "$C_CMD" bcmcmd -n "$_li_u" -c "ps $PORT" + printf ' ce0(%s) %s 4 100G FD (dry-run)\n' \ + "$PORT" "$([ "$_li_want" = up ] && echo 'up ' || echo '!ena')" >> "$STATUS_TMP" + continue + fi + [ "$DEBUG" = "1" ] && _show_cmd '[CMD]' "$C_CMD" bcmcmd -n "$_li_u" -c "ps $PORT" + bcmcmd -n "$_li_u" -c "ps $PORT" < /dev/null >> "$STATUS_TMP" 2>&1 + naptime "$CMD_DELAY" + done + + # The data row is the one whose first field ends in "()"; the state + # is the field right after it. "down" is "not up", so !ena counts. + awk -v port="$PORT" -v want="$_li_want" -v units="$(echo "$UNITS" | wc -w)" ' + $1 ~ ("\\(" port "\\)$") { + n++ + if (want == "up") { if ($2 != "up") bad++ } + else { if ($2 == "up") bad++ } + } + END { exit (n >= units && bad == 0) ? 0 : 1 } + ' "$STATUS_TMP" +} + +# $1 = wanted state (Down/up), $2 = label for the messages +wait_link() { + _wl_want="$1"; _wl_tag="$2" + _wl_waited=0 + while :; do + if link_is "$_wl_want"; then + { + printf '\n--- port %s after %ss ---\n' "$_wl_want" "$_wl_waited" + cat "$STATUS_TMP" + } | tee_log + ok "$_wl_tag : port $_wl_want after ${_wl_waited}s" + return 0 + fi + [ "$_wl_waited" -ge "$LINK_WAIT" ] && break + naptime "$POLL" + _wl_waited=$((_wl_waited + POLL)) + done + { + printf '\n--- TIMEOUT waiting for port %s (%ss) ---\n' "$_wl_want" "$LINK_WAIT" + cat "$STATUS_TMP" + } | tee_log + err "$_wl_tag : TIMEOUT waiting for port $_wl_want (${LINK_WAIT}s)" + return 1 +} + +port_en() { + for _pe_u in $UNITS; do + runq bcmcmd -n "$_pe_u" -c "port ${PORT} en=$1" + done +} + +# ---------------------------------------------------------------------------- +# Log header +# ---------------------------------------------------------------------------- +{ + printf '=====================================================================\n' + printf '100G DSC cycle test\n' + printf ' script : bcm_100g_dsc_cycle.sh V1.2.0\n' + printf ' started : %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" + printf ' cycles : %s\n' "$CYCLES" + printf ' port : %s units : %s\n' "$PORT" "$UNITS" + printf ' tuning : %s\n' "$([ "$DOTUNE" = 1 ] && echo yes || echo 'skipped (-T)')" + printf ' tx lanes : %s\n' "$TX_LANES" + printf ' rx lanes : %s\n' "$RX_LANES" + printf ' link wait: %ss poll %ss settle %ss cmd delay %ss\n' \ + "$LINK_WAIT" "$POLL" "$SETTLE" "$CMD_DELAY" + printf '=====================================================================\n' +} >> "$LOG" + +info "log : $LOG" + +# ---------------------------------------------------------------------------- +# 1. Tuning, once +# ---------------------------------------------------------------------------- +if [ "$DOTUNE" = "1" ]; then + info "Tuning" + printf '\n### TUNING %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG" + + if [ "$PAUSE_GBSYNCD" = "1" ]; then + for c in $GBSYNCD; do + if runq $SUDO docker pause "$c"; then + PAUSED=1 + info "gbsyncd paused: $c" + else + warn "docker pause $c failed (container not running?)" + fi + done + fi + + run $SUDO /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 0 2>&1 | tee_log + + for l in $SYS_LANES; do + # shellcheck disable=SC2086 + run $SUDO /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys "$l" $SYS_TX 2>&1 | tee_log + done + + echo "$TX_TAPS" | while read -r u lane main pre1 post1; do + [ -n "${u:-}" ] || continue + run bcmcmd -n "$u" -c \ + " dsh -c 'phydiag ${PORT} tx_taps set lane=${lane} main=${main} pre1=${pre1} post1=${post1}' " \ + 2>&1 | tee_log + done + + ok "Tuning done" +fi + +# ---------------------------------------------------------------------------- +# 2. Test cycles +# ---------------------------------------------------------------------------- +n=1 +while [ "$n" -le "$CYCLES" ]; do + tag="Test Cycle $n / $CYCLES" + + printf '\n\n### TEST CYCLE %s/%s %s\n' "$n" "$CYCLES" \ + "$(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG" + + # ---- Disable Port ------------------------------------------------------ + info "$tag : Disable Port" + port_en 0 + + info "$tag : Wait Port Link Down" + wait_link down "$tag" || RC=1 + + # ---- Enable Port ------------------------------------------------------- + info "$tag : Enable Port" + port_en 1 + + info "$tag : Wait Link up" + if wait_link up "$tag"; then + naptime "$SETTLE" + else + RC=1 + fi + + # ---- Collect ----------------------------------------------------------- + # Written to a per-cycle temp file first, then appended. Appending to the + # log and then re-reading it to check would mean re-reading an ever larger + # file every round - O(n^2) over 200 cycles. + info "$tag : Collect Data" + : > "$CYCLE_TMP" + for u in $UNITS; do + { + printf '\n--- phydiag %s dsc : unit %s ---\n' "$PORT" "$u" + run bcmcmd -n "$u" -c "dsh -c 'phydiag ${PORT} dsc'" 2>&1 + } >> "$CYCLE_TMP" + done + + info "$tag : Read Retimer TX" + for l in $TX_LANES; do + { + printf '\n--- serdes-tx-get sys %s ---\n' "$l" + run $SUDO /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys "$l" 2>&1 + } >> "$CYCLE_TMP" + done + + info "$tag : Read Retimer RX" + for l in $RX_LANES; do + { + printf '\n--- serdes-rx-get sys %s ---\n' "$l" + run $SUDO /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys "$l" 2>&1 + } >> "$CYCLE_TMP" + done + + cat "$CYCLE_TMP" >> "$LOG" + + if [ "$DRYRUN" = "0" ]; then + # bcmcmd exits 0 even when it failed, so count the end marker instead + got=$(grep -c 'SERDES DISPLAY DIAG DATA END' "$CYCLE_TMP" 2>/dev/null || true) + want=$(echo "$UNITS" | wc -w) + if [ "${got:-0}" -lt "$want" ]; then + err "$tag : got only ${got:-0}/${want} DSC dumps" + RC=1 + fi + + # The section headings are printed by this script, so counting them + # only proves the loop ran. Count sections that have output under them. + for d in tx rx; do + case "$d" in + tx) wantl="$TX_LANES" ;; + rx) wantl="$RX_LANES" ;; + esac + got_l=$(awk -v pat="--- serdes-${d}-get sys " ' + index($0, pat) == 1 { if (insec && body) ok++; insec = 1; body = 0; next } + /^--- / || /^### / { if (insec && body) ok++; insec = 0; next } + insec && NF { body = 1 } + END { if (insec && body) ok++; print ok + 0 } + ' "$CYCLE_TMP") + want_l=$(echo "$wantl" | wc -w) + if [ "${got_l:-0}" -lt "$want_l" ]; then + err "$tag : retimer $(echo "$d" | tr 'a-z' 'A-Z') returned data for only ${got_l:-0}/${want_l} lanes" + RC=1 + fi + done + fi + + n=$((n + 1)) +done + +resume_gbsyncd + +printf '\n### DSC_CYCLE_DONE rc=%s\n' "$RC" >> "$LOG" +if [ "$RC" = "0" ]; then + ok "all $CYCLES cycles done -> $LOG" +else + err "some cycles did not complete as expected - see $LOG" +fi +printf '### DSC_CYCLE_DONE rc=%s\n' "$RC" +exit "$RC" diff --git a/tools/100G_dsc_cycle.txt b/tools/100G_dsc_cycle.txt new file mode 100644 index 0000000..1b3197b --- /dev/null +++ b/tools/100G_dsc_cycle.txt @@ -0,0 +1,90 @@ +cd /usr/sbin +sudo docker pause gbsyncd1 +sudo docker pause gbsyncd0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 0 + +//Tuning +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys 0 pre=-10 main=87 post=0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys 1 pre=-10 main=87 post=0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys 2 pre=-10 main=87 post=0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys 3 pre=-10 main=87 post=0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys 4 pre=-10 main=87 post=0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys 5 pre=-10 main=87 post=0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys 6 pre=-10 main=87 post=0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-set sys 7 pre=-10 main=87 post=0 +bcmcmd -n 0 -c " dsh -c 'phydiag 268 tx_taps set lane=0 main=31 pre1=4 post1=13' " +bcmcmd -n 0 -c " dsh -c 'phydiag 268 tx_taps set lane=1 main=31 pre1=4 post1=13' " +bcmcmd -n 0 -c " dsh -c 'phydiag 268 tx_taps set lane=2 main=27 pre1=4 post1=13' " +bcmcmd -n 0 -c " dsh -c 'phydiag 268 tx_taps set lane=3 main=29 pre1=4 post1=13' " +bcmcmd -n 1 -c " dsh -c 'phydiag 268 tx_taps set lane=0 main=29 pre1=4 post1=13' " +bcmcmd -n 1 -c " dsh -c 'phydiag 268 tx_taps set lane=1 main=30 pre1=4 post1=13' " +bcmcmd -n 1 -c " dsh -c 'phydiag 268 tx_taps set lane=2 main=31 pre1=4 post1=13' " +bcmcmd -n 1 -c " dsh -c 'phydiag 268 tx_taps set lane=3 main=30 pre1=4 post1=13' " + +以下Test Cycle 目標200次 +//Disable Port +bcmcmd -n 0 -c "port 268 en=0" +bcmcmd -n 1 -c "port 268 en=0" + +//Wait Link Down +bcmcmd -n 0 -c "ps 268" +bcmcmd -n 1 -c "ps 268" +root@sonic:~# bcmcmd -n 0 -c "ps 268" +ps 268 + ena/ speed/ link auto STP lrn max cut loop + port link Lns duplex scan neg? state pause discrd ops medium frame thru FEC back + ce0(268) !ena 4 100G FD SW No Forward Untag FA Backplane 9122 No RS528 +drivshell> +root@sonic:~# bcmcmd -n 1 -c "ps 268" +ps 268 + ena/ speed/ link auto STP lrn max cut loop + port link Lns duplex scan neg? state pause discrd ops medium frame thru FEC back + ce0(268) !ena 4 100G FD SW No Forward Untag FA Backplane 9122 No RS528 +drivshell> +root@sonic:~# + + +//Enable Port +bcmcmd -n 0 -c "port 268 en=1" +bcmcmd -n 1 -c "port 268 en=1" + +//Wait Link Up +bcmcmd -n 0 -c "ps 268" +bcmcmd -n 1 -c "ps 268" +root@sonic:~# bcmcmd -n 0 -c "ps 268" +ps 268 + ena/ speed/ link auto STP lrn max cut loop + port link Lns duplex scan neg? state pause discrd ops medium frame thru FEC back + ce0(268) up 4 100G FD SW No Forward Untag FA Backplane 9122 No RS528 +drivshell> +root@sonic:~# bcmcmd -n 1 -c "ps 268" +ps 268 + ena/ speed/ link auto STP lrn max cut loop + port link Lns duplex scan neg? state pause discrd ops medium frame thru FEC back + ce0(268) up 4 100G FD SW No Forward Untag FA Backplane 9122 No RS528 +drivshell> +root@sonic:~# + + +//Collect DSC Data +bcmcmd -n 0 -c "dsh -c 'phydiag 268 dsc'" +bcmcmd -n 1 -c "dsh -c 'phydiag 268 dsc'" + +//讀Retimer TX/RX +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 1 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 2 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 3 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 4 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 5 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 6 +sudo /usr/sbin/blanton_barchetta_tool --serdes-tx-get sys 7 + +sudo /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys 0 +sudo /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys 1 +sudo /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys 2 +sudo /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys 3 +sudo /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys 4 +sudo /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys 5 +sudo /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys 6 +sudo /usr/sbin/blanton_barchetta_tool --serdes-rx-get sys 7 \ No newline at end of file