Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
metadata:
name: CAN_Internal_Loopback_Validation
format: "Lava-Test Test Definition 1.0"
description: "Run transactional exact-frame loopback on all safe auto-detected or one selected CAN interface"
os:
- linux
scope:
- functional

params:
CAN_INTERFACE: ""
CAN_LOOPBACK_MODE: "auto"
CAN_BITRATE: "500000"
CAN_DBITRATE: "2000000"
CAN_LOOPBACK_TIMEOUT: "10"

run:
steps:
- REPO_PATH=$PWD
- cd Runner/suites/Kernel/Baseport/CAN_Internal_Loopback_Validation
- CAN_INTERFACE="${CAN_INTERFACE}" CAN_LOOPBACK_MODE="${CAN_LOOPBACK_MODE}" CAN_BITRATE="${CAN_BITRATE}" CAN_DBITRATE="${CAN_DBITRATE}" CAN_LOOPBACK_TIMEOUT="${CAN_LOOPBACK_TIMEOUT}" ./run.sh || true
- $REPO_PATH/Runner/utils/send-to-lava.sh CAN_Internal_Loopback_Validation.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# CAN internal loopback validation

`CAN_Internal_Loopback_Validation` sends and receives exact SocketCAN frames
through an auto-detected or explicitly selected physical CAN controller in
internal-loopback mode.

For safety, the suite requires each interface to be initially down. It configures
each selected interface with a default 500 kbit/s arbitration bitrate and a
2 Mbit/s CAN FD data bitrate. An active CAN interface is never taken over
automatically. Every physical interface meeting these readiness conditions is
selected automatically and validated sequentially.

The suite restores the interface to down and restores the original bitrate,
data bitrate, CAN FD, and loopback settings when they were initially exposed.
Linux does not provide a portable operation to return a previously unconfigured
physical CAN interface to an unconfigured timing state. In that case the test
leaves the interface down with the test bitrate configured and reports that
state in stdout.

Classic mode validates both an 11-bit identifier and a 29-bit extended
identifier. Automatic mode attempts a CAN-FD frame using the default data
bitrate and records a clean skip when the controller rejects CAN FD. Every case
requires RX and TX packet counters to increase and error counters not to
increase when sysfs exposes those counters.

## Prepare and run

Run automatic CAN loopback with the default bitrates:

```sh
cd Runner/suites/Kernel/Baseport/CAN_Internal_Loopback_Validation
./run.sh
```

Override the selected interface or timing when required:

```sh
./run.sh --interface can0 --mode auto --bitrate 500000 --dbitrate 2000000
```

Use `--interface` or `CAN_INTERFACE` to override automatic discovery.
`CAN_BITRATE` and `CAN_DBITRATE` override the timing defaults. CLI options take
precedence over environment variables.

With no override, the suite discovers and sequentially validates every down
physical CAN interface. Use `--interface` or `CAN_INTERFACE` to restrict
validation to one interface. The test uses image-provided `ip`, `candump`, and
`cansend` only and skips cleanly when those optional utilities are absent.

Command and frame evidence is retained under
`results/CAN_Internal_Loopback_Validation/run-*/<interface>/`. The
live log retains the per-object failure analysis needed for remote debugging.

## Result policy

- `PASS`: all applicable exact frames are observed, packet counters increase,
error counters remain stable, and state restoration succeeds.
- `FAIL`: the selected object is not physical CAN hardware, configuration,
transfer, frame validation, or restoration fails.
- `SKIP`: no ready physical interface is discovered, required image-provided
tools are absent, or CAN FD is unavailable during automatic mode.

Reference: [Qualcomm Linux CAN guide](https://docs.qualcomm.com/doc/80-70023-8/topic/can.html)
232 changes: 232 additions & 0 deletions Runner/suites/Kernel/Baseport/CAN_Internal_Loopback_Validation/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
#!/bin/sh
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: BSD-3-Clause

# ---------- Repo env + helpers ----------
SCRIPT_DIR="$(
cd "$(dirname "$0")" || exit 1
pwd
)"
INIT_ENV=""
SEARCH="$SCRIPT_DIR"

while [ "$SEARCH" != "/" ]; do
if [ -f "$SEARCH/init_env" ]; then
INIT_ENV="$SEARCH/init_env"
break
fi
SEARCH=$(dirname "$SEARCH")
done

if [ -z "$INIT_ENV" ]; then
echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2
exit 1
fi

# Only source once (idempotent)
# NOTE: We intentionally **do not export** any new vars. They stay local to this shell.
if [ -z "${__INIT_ENV_LOADED:-}" ]; then
# shellcheck disable=SC1090
. "$INIT_ENV"
__INIT_ENV_LOADED=1
fi

# shellcheck disable=SC1090
. "$INIT_ENV"
# shellcheck disable=SC1091
. "$TOOLS/functestlib.sh"
# shellcheck disable=SC1091
. "$TOOLS/lib_bus.sh"
TESTNAME="CAN_Internal_Loopback_Validation"
RES_FILE="$SCRIPT_DIR/$TESTNAME.res"

RESULT_DIR="$SCRIPT_DIR/results/$TESTNAME/run-$(date '+%Y%m%d-%H%M%S')-$$"
CAN_INTERFACE="${CAN_INTERFACE:-}"
CAN_LOOPBACK_MODE="${CAN_LOOPBACK_MODE:-auto}"
CAN_BITRATE="${CAN_BITRATE:-500000}"
CAN_DBITRATE="${CAN_DBITRATE:-2000000}"
CAN_LOOPBACK_TIMEOUT="${CAN_LOOPBACK_TIMEOUT:-10}"

cleanup() {
can_internal_loopback_cleanup >/dev/null 2>&1 || true
}

usage() {
cat <<EOF
Usage: $0 [options]
--interface NAME Override auto-detection with a physical CAN interface
--mode auto|classic|fd
Frame modes, default: $CAN_LOOPBACK_MODE
--bitrate BPS Classic arbitration bitrate, default: $CAN_BITRATE
--dbitrate BPS CAN FD data bitrate, default: $CAN_DBITRATE
--timeout SECONDS Receive timeout, default: $CAN_LOOPBACK_TIMEOUT
-h, --help Show this help

The interface must initially be down. The test applies the requested bitrates.
EOF
}

parse_args() {
while [ "$#" -gt 0 ]; do
case "$1" in
--interface)
[ "$#" -ge 2 ] || return 2
CAN_INTERFACE="$2"
shift 2
;;
--mode)
[ "$#" -ge 2 ] || return 2
CAN_LOOPBACK_MODE="$2"
shift 2
;;
--bitrate)
[ "$#" -ge 2 ] || return 2
CAN_BITRATE="$2"
shift 2
;;
--dbitrate)
[ "$#" -ge 2 ] || return 2
CAN_DBITRATE="$2"
shift 2
;;
--timeout)
[ "$#" -ge 2 ] || return 2
CAN_LOOPBACK_TIMEOUT="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
log_error "Unknown argument: $1"
return 2
;;
esac
done
}

validate_config() {
case "$CAN_LOOPBACK_MODE" in
auto|classic|fd)
;;
*)
log_error "Unsupported CAN loopback mode: $CAN_LOOPBACK_MODE"
return 2
;;
esac
for numeric_value in "$CAN_LOOPBACK_TIMEOUT" "$CAN_BITRATE" "$CAN_DBITRATE"; do
case "$numeric_value" in
''|*[!0-9]*|0)
log_error "CAN timeout, bitrate, and data bitrate must be positive integers"
return 2
;;
esac
done
}

if ! parse_args "$@"; then
usage >&2
exit 2
fi
if ! validate_config; then
usage >&2
exit 2
fi

test_result_init "$TESTNAME" "$RES_FILE" || exit 1
trap cleanup EXIT HUP INT TERM

if ! mkdir -p "$RESULT_DIR"; then
test_result_finish "FAIL" "$TESTNAME FAIL: cannot create retained evidence directory $RESULT_DIR"
fi

log_info "--------------------------------------------------------------------------"
log_info "Starting $TESTNAME"
log_info "Evidence directory: $RESULT_DIR"
CAN_SELECTION_SOURCE=override
CAN_SELECTED_INTERFACES="$RESULT_DIR/can_selected_interfaces.log"
: >"$CAN_SELECTED_INTERFACES"
if [ -n "$CAN_INTERFACE" ]; then
if ! can_internal_loopback_interface_is_ready "$CAN_INTERFACE"; then
test_result_finish "FAIL" "$TESTNAME FAIL: requested interface $CAN_INTERFACE is not a down physical SocketCAN interface"
fi
printf '%s\n' "$CAN_INTERFACE" >"$CAN_SELECTED_INTERFACES"
else
CAN_SELECTION_SOURCE=auto-all
can_internal_loopback_list_interfaces "$CAN_LOOPBACK_MODE" >"$CAN_SELECTED_INTERFACES" 2>/dev/null
CAN_SELECTION_STATUS=$?
if [ "$CAN_SELECTION_STATUS" -eq 3 ]; then
test_result_finish "FAIL" "$TESTNAME FAIL: unsupported CAN loopback mode $CAN_LOOPBACK_MODE"
fi
fi
if [ ! -s "$CAN_SELECTED_INTERFACES" ]; then
test_result_finish "SKIP" "$TESTNAME SKIP: no down physical CAN interface was detected"
fi
if ! bus_validation_require_commands awk candump cansend cat grep ip mkdir sed sleep tr; then
test_result_finish "SKIP" "$TESTNAME SKIP: image-provided ip or CAN-utils are unavailable"
fi
log_info "CAN loopback: validating standard, extended, and available FD frame paths while checking packet and error-counter deltas"
CAN_SELECTED_COUNT=$(awk 'NF { count++ } END { print count + 0 }' "$CAN_SELECTED_INTERFACES")
log_info "CAN selection: source=$CAN_SELECTION_SOURCE selected_interfaces=$CAN_SELECTED_COUNT list=$CAN_SELECTED_INTERFACES"
while IFS= read -r CAN_INTERFACE; do
[ -n "$CAN_INTERFACE" ] || continue
CAN_INTERFACE_RESULT_DIR="$RESULT_DIR/$CAN_INTERFACE"
if ! mkdir -p "$CAN_INTERFACE_RESULT_DIR"; then
test_result_record "FAIL" "CAN evidence directory could not be created for $CAN_INTERFACE at $CAN_INTERFACE_RESULT_DIR"
continue
fi
log_info "[CAN-SELECTION] interface=$CAN_INTERFACE source=$CAN_SELECTION_SOURCE"
CAN_LOOPBACK_MODES=$CAN_LOOPBACK_MODE
if [ "$CAN_LOOPBACK_MODE" = "auto" ]; then
CAN_LOOPBACK_MODES=$(can_internal_loopback_select_modes "$CAN_INTERFACE")
CAN_MODE_SELECTION_STATUS=$?
if [ "$CAN_MODE_SELECTION_STATUS" -ne 0 ] || [ -z "$CAN_LOOPBACK_MODES" ]; then
test_result_record "FAIL" "Could not derive loopback modes for $CAN_INTERFACE"
continue
fi
fi
log_info "Configuration: interface=$CAN_INTERFACE selection=$CAN_SELECTION_SOURCE modes=$CAN_LOOPBACK_MODES bitrate=$CAN_BITRATE dbitrate=$CAN_DBITRATE timeout=${CAN_LOOPBACK_TIMEOUT}s evidence=$CAN_INTERFACE_RESULT_DIR"
CAN_REMAINING_MODES=$CAN_LOOPBACK_MODES
while [ -n "$CAN_REMAINING_MODES" ]; do
case "$CAN_REMAINING_MODES" in
*,*)
CAN_MODE=${CAN_REMAINING_MODES%%,*}
CAN_REMAINING_MODES=${CAN_REMAINING_MODES#*,}
;;
*)
CAN_MODE=$CAN_REMAINING_MODES
CAN_REMAINING_MODES=""
;;
esac
log_info "---- CAN functional case: interface=$CAN_INTERFACE mode=$CAN_MODE ----"
can_internal_loopback_validate \
"$CAN_INTERFACE" \
"$CAN_MODE" \
"$CAN_LOOPBACK_TIMEOUT" \
"$CAN_INTERFACE_RESULT_DIR" \
"$CAN_BITRATE" \
"$CAN_DBITRATE"
loopback_status=$?
case "$loopback_status" in
0)
test_result_record "PASS" "CAN $CAN_MODE internal loopback frames and counter deltas passed on $CAN_INTERFACE"
;;
1)
test_result_record "FAIL" "CAN $CAN_MODE internal loopback failed on $CAN_INTERFACE, see $CAN_INTERFACE_RESULT_DIR/can_loopback_rx_${CAN_MODE}.log and $CAN_INTERFACE_RESULT_DIR/can_loopback_statistics_${CAN_MODE}.log"
;;
2)
if [ "$CAN_LOOPBACK_MODE" = "fd" ]; then
test_result_record "FAIL" "CAN FD was explicitly requested but $CAN_INTERFACE rejected bitrate=$CAN_BITRATE dbitrate=$CAN_DBITRATE configuration"
else
test_result_record "SKIP" "$CAN_INTERFACE does not accept the automatic $CAN_MODE configuration"
fi
;;
*)
test_result_record "FAIL" "CAN loopback helper returned unexpected status $loopback_status for mode $CAN_MODE"
;;
esac
done
done <"$CAN_SELECTED_INTERFACES"

test_result_finish
15 changes: 15 additions & 0 deletions Runner/suites/Kernel/Baseport/CAN_Validation/CAN_Validation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
metadata:
name: CAN_Validation
format: "Lava-Test Test Definition 1.0"
description: "Validate CAN controller binding and SocketCAN runtime readiness"
os:
- linux
scope:
- functional

run:
steps:
- REPO_PATH=$PWD
- cd Runner/suites/Kernel/Baseport/CAN_Validation
- ./run.sh || true
- $REPO_PATH/Runner/utils/send-to-lava.sh CAN_Validation.res
39 changes: 39 additions & 0 deletions Runner/suites/Kernel/Baseport/CAN_Validation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# CAN validation

`CAN_Validation` validates CAN hardware readiness from runtime DT and SocketCAN
interfaces. It does not assume `can0`, a fixed SPI bus, chip select, board, SoC,
or a single valid CAN controller driver.

For each capability, the suite reports the parent runtime device, bound driver,
DT identity, SocketCAN interface, administrative state, CAN protocol state,
classic and CAN FD bitrates, controller mode, bus error counters, and network
RX/TX error counters. Detailed `ip` output is retained when the image provides
the tool.

## Run

```sh
cd Runner/suites/Kernel/Baseport/CAN_Validation
./run.sh
```

## Result policy

- `PASS`: every discovered CAN declaration has a bound runtime device and
SocketCAN interface.
- `FAIL`: a declared CAN device is missing, unbound, lacks its SocketCAN
interface, reports a current error-warning, error-passive, or bus-off state,
or persistent CAN or parent-SPI kernel errors are present.
- `SKIP`: no enabled or runtime-visible CAN capability exists.

## Diagnostics

The suite emits bounded per-device binding, SocketCAN, and kernel-health
diagnostics to stdout. Evidence is retained under
`results/CAN_Validation/run-*/`.

Internal and external traffic validation are intentionally separate because
they change interface state and require either controlled loopback or external
fixtures with reliable cleanup.

Reference: [Qualcomm Linux CAN guide](https://docs.qualcomm.com/doc/80-70023-8/topic/can.html)
Loading
Loading