From 9e025f7f50e42c3825a0d9b7f6e2f5048b1dac76 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Sat, 27 Jun 2026 23:07:31 +0530 Subject: [PATCH 1/5] Module_Reload_Validation: add generic reload framework helpers Add generic module reload helpers in lib_module_reload.sh for profile-driven module unload/reload validation. The helpers cover module availability checks, holder discovery, timeout-wrapped load/unload commands, multi-module validation, service/process quiesce, best-effort restore, open-FD evidence, and per-iteration debug collection. Keep module-specific behavior out of run.sh and allow profiles to stay mostly declarative. Signed-off-by: Srikanth Muppandam --- Runner/utils/lib_module_reload.sh | 693 ++++++++++++++++++++++++++++-- 1 file changed, 647 insertions(+), 46 deletions(-) diff --git a/Runner/utils/lib_module_reload.sh b/Runner/utils/lib_module_reload.sh index a28380d1e..923f31a71 100755 --- a/Runner/utils/lib_module_reload.sh +++ b/Runner/utils/lib_module_reload.sh @@ -1,12 +1,13 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause-Clear +# SPDX-License-Identifier: BSD-3-Clause MRV_LAST_CMD_PID="" MRV_LAST_CMD_ELAPSED="0" MRV_LAST_TIMEOUT_DIR="" MRV_PROFILE_REASON="" +# Reset all profile-provided variables before sourcing a profile. mrv_reset_profile_vars() { PROFILE_NAME="" PROFILE_DESCRIPTION="" @@ -21,17 +22,190 @@ mrv_reset_profile_vars() { PROFILE_DEVICE_PATTERNS="" PROFILE_SYSFS_PATTERNS="" PROFILE_SELECTED_MODE="" + PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="" + PROFILE_EXPECT_PRESENT_AFTER_LOAD="" + PROFILE_SKIP_IF_MODULES_LOADED="" + PROFILE_TOP_MODULE_CANDIDATES="" + PROFILE_UNLOAD_STACK="" + PROFILE_EXTRA_UNLOAD_MODULES="" + PROFILE_QUIESCE_SERVICES="" + PROFILE_QUIESCE_PROC_PATTERNS="" + PROFILE_QUIESCE_DEVICE_PATTERNS="" + PROFILE_QUIESCE_ONCE="no" + MRV_PROFILE_QUIESCED="0" } +# Convert module names to the form used by lsmod and /proc/modules. mrv_module_lsmod_name() { printf '%s\n' "$1" | tr '-' '_' } +# Return success when a module is either loaded or available through modinfo. +mrv_module_available() { + mod="$1" + + if mrv_module_loaded "$mod"; then + return 0 + fi + + if modinfo "$mod" >/dev/null 2>&1; then + return 0 + fi + + return 1 +} + +# Return the first sysfs holder for a module, if any. +mrv_module_first_holder_sysfs() { + mod="$1" + + for holder_path in /sys/module/"$mod"/holders/*; do + [ -e "$holder_path" ] || continue + holder="${holder_path##*/}" + [ -n "$holder" ] || continue + printf '%s\n' "$holder" + return 0 + done + + return 1 +} + +# Return the first /proc/modules holder for a module, if any. +mrv_module_first_holder_proc() { + mod="$1" + + [ -r /proc/modules ] || return 1 + + awk -v target="$mod" ' + $1 == target && $4 != "-" { + n = split($4, holders, ",") + for (i = 1; i <= n; i++) { + if (holders[i] != "") { + print holders[i] + exit + } + } + } + ' /proc/modules 2>/dev/null +} + +# Select the reload target for a stack: holder first, candidates second, primary last. +mrv_select_reload_top_module() { + primary="$1" + candidates="$2" + top_module="" + + top_module="$(mrv_module_first_holder_sysfs "$primary" 2>/dev/null || true)" + if [ -n "$top_module" ]; then + printf '%s\n' "$top_module" + return 0 + fi + + top_module="$(mrv_module_first_holder_proc "$primary" 2>/dev/null || true)" + if [ -n "$top_module" ]; then + printf '%s\n' "$top_module" + return 0 + fi + + for candidate in $candidates; do + [ -n "$candidate" ] || continue + if mrv_module_available "$candidate"; then + printf '%s\n' "$candidate" + return 0 + fi + done + + if mrv_module_available "$primary"; then + printf '%s\n' "$primary" + return 0 + fi + + return 1 +} + +# Configure generic stack reload commands from profile data. +# +# Profiles can define: +# MODULE_NAME primary module +# PROFILE_TOP_MODULE_CANDIDATES optional holder/top-module candidates +# PROFILE_UNLOAD_STACK explicit unload order +# PROFILE_EXTRA_UNLOAD_MODULES extra modules to unload after stack +# +# This helper intentionally avoids ${var:-command-with-${m}} expansion because +# nested braces inside command strings can break POSIX shell parsing. +module_reload_profile_setup_stack() { + primary="${MODULE_NAME:-}" + top_module="" + unload_stack="" + + if [ -z "$primary" ]; then + MODULE_RELOAD_SUPPORTED="no" + return 0 + fi + + top_module="$(mrv_select_reload_top_module "$primary" "$PROFILE_TOP_MODULE_CANDIDATES" 2>/dev/null || true)" + if [ -z "$top_module" ]; then + MODULE_RELOAD_SUPPORTED="no" + return 0 + fi + + MODULE_NAME="$top_module" + MODULE_RELOAD_SUPPORTED="${MODULE_RELOAD_SUPPORTED:-yes}" + + if [ -n "$PROFILE_UNLOAD_STACK" ]; then + unload_stack="$PROFILE_UNLOAD_STACK" + elif [ "$top_module" != "$primary" ]; then + unload_stack="$top_module $primary" + else + unload_stack="$primary" + fi + + if [ -n "$PROFILE_EXTRA_UNLOAD_MODULES" ]; then + unload_stack="$unload_stack $PROFILE_EXTRA_UNLOAD_MODULES" + fi + + if [ -z "$MODULE_UNLOAD_CMD" ]; then + MODULE_UNLOAD_CMD="modprobe -r $unload_stack" + fi + + if [ -z "$MODULE_LOAD_CMD" ]; then + MODULE_LOAD_CMD="modprobe $top_module" + fi + + if [ -z "$PROFILE_EXPECT_ABSENT_AFTER_UNLOAD" ]; then + PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="$top_module" + fi + + if [ -z "$PROFILE_EXPECT_PRESENT_AFTER_LOAD" ]; then + PROFILE_EXPECT_PRESENT_AFTER_LOAD="$top_module" + fi + + return 0 +} + +# Return success when the module is present in lsmod. mrv_module_loaded() { name="$(mrv_module_lsmod_name "$1")" is_module_loaded "$name" } +# Return success when another mutually exclusive module variant is already active. +mrv_should_skip_for_loaded_conflict_modules() { + [ -n "$PROFILE_SKIP_IF_MODULES_LOADED" ] || return 1 + + for conflict_mod in $PROFILE_SKIP_IF_MODULES_LOADED; do + [ -n "$conflict_mod" ] || continue + + if mrv_module_loaded "$conflict_mod"; then + MRV_PROFILE_REASON="conflicting active module is loaded: $conflict_mod" + return 0 + fi + done + + return 1 +} + +# Return success when a module is built into the kernel and cannot be unloaded. mrv_module_builtin() { if [ -f "/lib/modules/$(uname -r)/modules.builtin" ]; then mod_pat="$(printf '%s\n' "$1" | sed 's/_/[-_]/g')" @@ -41,6 +215,7 @@ mrv_module_builtin() { return 1 } +# Wait until a module reaches the requested state: present or absent. mrv_wait_module_state() { want="$1" name="$2" @@ -72,6 +247,7 @@ mrv_wait_module_state() { return 0 } +# Capture existence and metadata for profile-provided path patterns. mrv_capture_patterns() { patterns="$1" outfile="$2" @@ -82,10 +258,12 @@ mrv_capture_patterns() { return 0 fi + # Intentional word splitting: patterns are space-separated profile data. # shellcheck disable=SC2086 set -- $patterns for pat in "$@"; do found=0 + # Intentional glob expansion from profile data. # shellcheck disable=SC2086 for path in $pat; do if [ -e "$path" ] || [ -L "$path" ]; then @@ -100,6 +278,7 @@ mrv_capture_patterns() { done } +# Capture status and recent logs for profile services. mrv_capture_services() { services="$1" outfile="$2" @@ -116,6 +295,7 @@ mrv_capture_services() { return 0 fi + # Intentional word splitting: services are space-separated profile data. # shellcheck disable=SC2086 set -- $services for svc in "$@"; do @@ -128,6 +308,7 @@ mrv_capture_services() { done } +# Capture module, process, service, sysfs, and device state for evidence. mrv_capture_module_state() { outdir="$1" mkdir -p "$outdir" @@ -169,7 +350,7 @@ mrv_capture_module_state() { printf '/sys/module/%s not present\n' "$sys_mod" > "$outdir/holders.log" fi - mrv_capture_services "$PROFILE_SERVICES" "$outdir/services.log" + mrv_capture_services "$PROFILE_SERVICES $PROFILE_QUIESCE_SERVICES" "$outdir/services.log" mrv_capture_patterns "$PROFILE_DEVICE_PATTERNS" "$outdir/devices.log" mrv_capture_patterns "$PROFILE_SYSFS_PATTERNS" "$outdir/profile_sysfs.log" @@ -178,6 +359,7 @@ mrv_capture_module_state() { fi } +# Capture /proc evidence for a command that timed out. mrv_capture_pid_timeout_snapshot() { pid="$1" outdir="$2" @@ -192,6 +374,7 @@ mrv_capture_pid_timeout_snapshot() { fi } +# Execute a shell command with timeout and command evidence logging. mrv_exec_with_timeout() { timeout_s="$1" logfile="$2" @@ -243,6 +426,7 @@ mrv_exec_with_timeout() { return "$rc" } +# Capture hang evidence after unload/load timeout. mrv_capture_hang_evidence() { phase="$1" outdir="$2" @@ -261,9 +445,11 @@ mrv_capture_hang_evidence() { if command -v fuser >/dev/null 2>&1; then : > "$outdir/fuser.log" + # Intentional word splitting: device patterns are profile data. # shellcheck disable=SC2086 set -- $PROFILE_DEVICE_PATTERNS for pat in "$@"; do + # Intentional glob expansion from profile data. # shellcheck disable=SC2086 for path in $pat; do if [ -e "$path" ] || [ -L "$path" ]; then @@ -285,11 +471,13 @@ mrv_capture_hang_evidence() { } > "$outdir/timeout_summary.log" } +# Return success when a profile hook function exists. mrv_profile_override_defined() { fn_name="$1" command -v "$fn_name" >/dev/null 2>&1 } +# Return success when a systemd service is known on the target. module_reload_service_known() { svc="$1" @@ -297,9 +485,10 @@ module_reload_service_known() { return 1 fi - systemctl list-unit-files "$svc" >/dev/null 2>&1 + systemctl show "$svc" >/dev/null 2>&1 } +# Read one systemd service state property. module_reload_service_state_value() { svc="$1" prop="$2" @@ -312,6 +501,86 @@ module_reload_service_state_value() { fi } +# Return the file used to track services stopped/masked by module reload tests. +# +# The file is under RESULT_ROOT so it is shared between the profile subshell and +# the top-level run.sh cleanup trap. +module_reload_restore_services_file() { + printf '%s\n' "${MRV_RESTORE_SERVICES_FILE:-${RESULT_ROOT:-/tmp}/.module_reload_services_to_restore}" +} + +# Record services before stopping/masking them. +# +# We store the previous ActiveState so final restore can avoid starting services +# that were already inactive before this test touched them. +module_reload_record_restore_services() { + services="$1" + restore_file="$(module_reload_restore_services_file)" + restore_dir="$(dirname "$restore_file")" + + [ -n "$services" ] || return 0 + + mkdir -p "$restore_dir" 2>/dev/null || true + + for svc in $services; do + [ -n "$svc" ] || continue + + if module_reload_service_known "$svc"; then + svc_state="$(module_reload_service_state_value "$svc" "ActiveState")" + + if [ ! -f "$restore_file" ] || ! grep -q "^${svc} " "$restore_file" 2>/dev/null; then + printf '%s %s\n' "$svc" "$svc_state" >> "$restore_file" + fi + fi + done + + return 0 +} + +# Restore every service previously stopped/masked by the module reload test. +# +# This is best-effort and should not fail the test. It unblocks the target after +# failed unloads, post-unload validation failures, timeouts, or interrupted runs. +# +# Services that were active before quiesce are started again. Services that were +# inactive before quiesce are only unmasked/reset, not force-started. +module_reload_restore_recorded_services() { + log_tag="${1:-module-reload}" + restore_file="$(module_reload_restore_services_file)" + + [ -f "$restore_file" ] || return 0 + + if ! command -v systemctl >/dev/null 2>&1; then + rm -f "$restore_file" 2>/dev/null || true + return 0 + fi + + while IFS=' ' read -r svc old_state rest || [ -n "$svc" ]; do + : "${rest:=}" + [ -n "$svc" ] || continue + + if module_reload_service_known "$svc"; then + log_info "[$log_tag] restore: unmasking/resetting $svc" + module_reload_run_cmd_quiet_timeout 5 systemctl unmask "$svc" || true + module_reload_run_cmd_quiet_timeout 5 systemctl reset-failed "$svc" || true + + case "$old_state" in + active|activating|reloading) + log_info "[$log_tag] restore: starting previously active service $svc" + module_reload_run_cmd_quiet_timeout 15 systemctl start "$svc" || true + ;; + *) + log_info "[$log_tag] restore: not starting $svc because previous state was ${old_state:-unknown}" + ;; + esac + fi + done < "$restore_file" + + rm -f "$restore_file" 2>/dev/null || true + return 0 +} + +# List process IDs whose command line contains a pattern. module_reload_list_pids_by_pattern() { proc_pat="$1" @@ -334,6 +603,7 @@ module_reload_list_pids_by_pattern() { done } +# Return success when any process matching a pattern is running. module_reload_proc_running_pattern() { proc_pat="$1" pids="$(module_reload_list_pids_by_pattern "$proc_pat")" @@ -344,6 +614,7 @@ module_reload_proc_running_pattern() { return 1 } +# Signal all processes whose command line contains a pattern. module_reload_signal_pattern() { proc_pat="$1" sig="$2" @@ -360,6 +631,7 @@ module_reload_signal_pattern() { return 0 } +# Wait until no processes match any pattern. module_reload_wait_no_procs_patterns() { proc_patterns="$1" timeout_s="${2:-10}" @@ -392,6 +664,7 @@ module_reload_wait_no_procs_patterns() { return 0 } +# Log current service states and matching process command lines. module_reload_log_service_process_summary() { services="$1" proc_patterns="$2" @@ -430,6 +703,7 @@ module_reload_log_service_process_summary() { done } +# Wait until all known services are active. module_reload_wait_services_active() { services="$1" timeout_s="${2:-15}" @@ -466,6 +740,7 @@ module_reload_wait_services_active() { return 0 } +# Wait until all known services are inactive. module_reload_wait_services_inactive() { services="$1" timeout_s="${2:-15}" @@ -502,54 +777,100 @@ module_reload_wait_services_inactive() { return 0 } +module_reload_run_cmd_quiet_timeout() { + timeout_s="$1" + shift + elapsed=0 + + if [ "$#" -eq 0 ]; then + return 1 + fi + + "$@" >/dev/null 2>&1 & + cmd_pid=$! + + while kill -0 "$cmd_pid" 2>/dev/null; do + if [ "$elapsed" -ge "$timeout_s" ] 2>/dev/null; then + kill -TERM "$cmd_pid" 2>/dev/null || true + sleep 1 + + if kill -0 "$cmd_pid" 2>/dev/null; then + kill -KILL "$cmd_pid" 2>/dev/null || true + sleep 1 + fi + + wait "$cmd_pid" 2>/dev/null || true + return 124 + fi + + sleep 1 + elapsed=$((elapsed + 1)) + done + + wait "$cmd_pid" + return $? +} + +# Start and unmask known services, then wait until active. module_reload_start_services() { services="$1" timeout_s="${2:-15}" log_tag="${3:-module-reload}" - + if ! command -v systemctl >/dev/null 2>&1; then return 0 fi - + for svc in $services; do if module_reload_service_known "$svc"; then - log_info "[$log_tag] start: unmasking and starting $svc" - systemctl unmask "$svc" >/dev/null 2>&1 || true - systemctl reset-failed "$svc" >/dev/null 2>&1 || true - systemctl start "$svc" >/dev/null 2>&1 || true + log_info "[$log_tag] start: unmasking $svc" + module_reload_run_cmd_quiet_timeout 5 systemctl unmask "$svc" || true + + log_info "[$log_tag] start: resetting $svc" + module_reload_run_cmd_quiet_timeout 5 systemctl reset-failed "$svc" || true + + log_info "[$log_tag] start: starting $svc" + module_reload_run_cmd_quiet_timeout "$timeout_s" systemctl start "$svc" || true fi done - + module_reload_wait_services_active "$services" "$timeout_s" } +# Stop, mask, and kill known services and matching processes. module_reload_stop_mask_kill_services() { services="$1" proc_patterns="$2" timeout_s="${3:-20}" log_tag="${4:-module-reload}" - + if ! command -v systemctl >/dev/null 2>&1; then return 0 fi - + + module_reload_record_restore_services "$services" + for svc in $services; do if module_reload_service_known "$svc"; then log_info "[$log_tag] quiesce: stopping $svc" - systemctl stop "$svc" >/dev/null 2>&1 || true + if ! module_reload_run_cmd_quiet_timeout "$timeout_s" systemctl stop "$svc"; then + log_warn "[$log_tag] quiesce: stop timed out or failed for $svc" + fi + log_info "[$log_tag] quiesce: masking $svc" - systemctl mask "$svc" >/dev/null 2>&1 || true + module_reload_run_cmd_quiet_timeout 5 systemctl mask "$svc" || true + log_info "[$log_tag] quiesce: killing remaining $svc cgroup processes" - systemctl kill --kill-who=all "$svc" >/dev/null 2>&1 || true + module_reload_run_cmd_quiet_timeout 5 systemctl kill --kill-who=all "$svc" || true fi done - + for proc_pat in $proc_patterns; do module_reload_signal_pattern "$proc_pat" TERM "$log_tag" done - + sleep 2 - + if ! module_reload_wait_no_procs_patterns "$proc_patterns" 5; then log_warn "[$log_tag] quiesce: TERM was not enough, sending SIGKILL to remaining processes" for proc_pat in $proc_patterns; do @@ -557,18 +878,21 @@ module_reload_stop_mask_kill_services() { done sleep 1 fi - + if ! module_reload_wait_services_inactive "$services" "$timeout_s"; then + log_warn "[$log_tag] quiesce: one or more services still not inactive after timeout" return 1 fi - + if ! module_reload_wait_no_procs_patterns "$proc_patterns" 2; then + log_warn "[$log_tag] quiesce: one or more process patterns still present after timeout" return 1 fi - + return 0 } +# Restore known services after a profile finishes. module_reload_restore_services() { services="$1" timeout_s="${2:-15}" @@ -590,6 +914,7 @@ module_reload_restore_services() { module_reload_wait_services_active "$services" "$timeout_s" } +# Dump status for a list of services to a file. module_reload_dump_service_status() { services="$1" svc_log="$2" @@ -611,6 +936,160 @@ module_reload_dump_service_status() { return 0 } +# Scan /proc/*/fd for open descriptors matching path patterns. +module_reload_scan_open_fds_by_path_patterns() { + path_patterns="$1" + out_file="$2" + + : > "$out_file" + + [ -n "$path_patterns" ] || return 1 + + for pid_dir in /proc/[0-9]*; do + [ -d "$pid_dir/fd" ] || continue + pid="${pid_dir##*/}" + + for fd in "$pid_dir"/fd/*; do + [ -e "$fd" ] || continue + + target="$(readlink "$fd" 2>/dev/null || true)" + [ -n "$target" ] || continue + for pat in $path_patterns; do + # Intentional glob pattern match from profile data. + # shellcheck disable=SC2254 + case "$target" in + $pat) + cmd="$(tr '\0' ' ' < "$pid_dir/cmdline" 2>/dev/null || true)" + [ -n "$cmd" ] || cmd="$(cat "$pid_dir/comm" 2>/dev/null || true)" + printf 'pid=%s fd=%s target=%s cmd=%s\n' "$pid" "${fd##*/}" "$target" "$cmd" >> "$out_file" + ;; + esac + done + done + done + + [ -s "$out_file" ] +} + +# Terminate processes that keep matching device paths open. +module_reload_kill_open_fd_users_by_path_patterns() { + path_patterns="$1" + timeout_s="${2:-10}" + log_tag="${3:-module-reload}" + out_file="${4:-/tmp/module_reload_open_fds.log}" + + if ! module_reload_scan_open_fds_by_path_patterns "$path_patterns" "$out_file"; then + return 0 + fi + + log_warn "[$log_tag] open users found for profiled device paths: $out_file" + + awk ' + { + for (i = 1; i <= NF; i++) { + if ($i ~ /^pid=/) { + sub(/^pid=/, "", $i) + print $i + } + } + } + ' "$out_file" | sort -u | while IFS= read -r pid; do + [ -n "$pid" ] || continue + [ "$pid" = "$$" ] && continue + log_warn "[$log_tag] sending SIGTERM to open-fd user pid=$pid" + kill -TERM "$pid" 2>/dev/null || true + done + + elapsed=0 + while [ "$elapsed" -lt "$timeout_s" ] 2>/dev/null; do + if ! module_reload_scan_open_fds_by_path_patterns "$path_patterns" "$out_file"; then + return 0 + fi + + sleep 1 + elapsed=$((elapsed + 1)) + done + + awk ' + { + for (i = 1; i <= NF; i++) { + if ($i ~ /^pid=/) { + sub(/^pid=/, "", $i) + print $i + } + } + } + ' "$out_file" | sort -u | while IFS= read -r pid; do + [ -n "$pid" ] || continue + [ "$pid" = "$$" ] && continue + log_warn "[$log_tag] sending SIGKILL to remaining open-fd user pid=$pid" + kill -KILL "$pid" 2>/dev/null || true + done + + sleep 1 + + if module_reload_scan_open_fds_by_path_patterns "$path_patterns" "$out_file"; then + log_warn "[$log_tag] open users still present after SIGKILL: $out_file" + return 1 + fi + + return 0 +} + +# Generic quiesce helper for services, process patterns, and open device users. +module_reload_profile_quiesce_resources() { + log_tag="${1:-$PROFILE_NAME}" + iter_dir="${2:-}" + timeout_s="${3:-20}" + + services="${PROFILE_QUIESCE_SERVICES:-$PROFILE_SERVICES}" + procs="${PROFILE_QUIESCE_PROC_PATTERNS:-$PROFILE_PROC_PATTERNS}" + devs="${PROFILE_QUIESCE_DEVICE_PATTERNS:-$PROFILE_DEVICE_PATTERNS}" + + module_reload_log_service_process_summary "$services" "$procs" "$log_tag" + + if [ -n "$services" ] || [ -n "$procs" ]; then + if ! module_reload_stop_mask_kill_services "$services" "$procs" "$timeout_s" "$log_tag"; then + log_warn "[$log_tag] service/process quiesce did not fully complete" + module_reload_log_service_process_summary "$services" "$procs" "$log_tag" + fi + fi + + if [ -n "$devs" ]; then + if [ -n "$iter_dir" ]; then + open_fd_log="$iter_dir/open_fds_before_unload.log" + else + open_fd_log="/tmp/module_reload_open_fds_before_unload.log" + fi + + if ! module_reload_kill_open_fd_users_by_path_patterns "$devs" 10 "$log_tag" "$open_fd_log"; then + log_warn "[$log_tag] open device users remain after quiesce; skipping unsafe unload" + return 1 + fi + fi + + sleep 2 + return 0 +} + +# Generic smoke helper that validates expected modules are loaded. +module_reload_profile_smoke_modules_present() { + log_tag="${1:-$PROFILE_NAME}" + modules="$2" + + [ -n "$modules" ] || modules="$MODULE_NAME" + + for mod in $modules; do + if ! mrv_module_loaded "$mod"; then + log_fail "[$log_tag] expected module not loaded after reload: $mod" + return 1 + fi + done + + return 0 +} + +# Dispatch optional profile prepare hook. module_reload_profile_prepare() { profile_root="$1" : "${profile_root:=}" @@ -623,6 +1102,7 @@ module_reload_profile_prepare() { return 0 } +# Dispatch optional warmup hook or generic daemon warmup. module_reload_profile_warmup() { iter_dir="$1" : "${iter_dir:=}" @@ -655,38 +1135,86 @@ module_reload_profile_warmup() { return 0 } +# Best-effort restore for services stopped/masked only for quiesce. +# +# Unlike module_reload_restore_services(), this does not require services to +# become active. This is needed for oneshot or optional services such as +# pulseaudio.service, alsa-restore.service, and distro-specific units. +module_reload_restore_quiesce_services_best_effort() { + services="$1" + log_tag="${2:-module-reload}" + + [ -n "$services" ] || return 0 + + if ! command -v systemctl >/dev/null 2>&1; then + return 0 + fi + + for svc in $services; do + if module_reload_service_known "$svc"; then + log_info "[$log_tag] restore: unmasking/resetting $svc" + systemctl unmask "$svc" >/dev/null 2>&1 || true + systemctl reset-failed "$svc" >/dev/null 2>&1 || true + log_info "[$log_tag] restore: starting $svc" + systemctl start "$svc" >/dev/null 2>&1 || true + fi + done + + return 0 +} + +# Dispatch optional quiesce hook or generic daemon quiesce. module_reload_profile_quiesce() { iter_dir="$1" : "${iter_dir:=}" - + if mrv_profile_override_defined profile_quiesce; then profile_quiesce "$iter_dir" return $? fi - - if ! command -v systemctl >/dev/null 2>&1; then + + quiesce_services="${PROFILE_QUIESCE_SERVICES:-$PROFILE_SERVICES}" + quiesce_proc_patterns="${PROFILE_QUIESCE_PROC_PATTERNS:-$PROFILE_PROC_PATTERNS}" + + if [ -z "$quiesce_services" ] && [ -z "$quiesce_proc_patterns" ]; then return 0 fi - + + if [ "${PROFILE_QUIESCE_ONCE:-no}" = "yes" ] && [ "${MRV_PROFILE_QUIESCED:-0}" = "1" ]; then + log_info "[$PROFILE_NAME] quiesce: already completed once for this profile, skipping repeated quiesce" + return 0 + fi + + module_reload_log_service_process_summary \ + "$quiesce_services" \ + "$quiesce_proc_patterns" \ + "$PROFILE_NAME" + case "$PROFILE_SELECTED_MODE" in - basic) - return 0 - ;; - daemon_lifecycle|service_rebind) - if ! module_reload_stop_mask_kill_services "$PROFILE_SERVICES" "$PROFILE_PROC_PATTERNS" 20 "$PROFILE_NAME"; then - module_reload_log_service_process_summary "$PROFILE_SERVICES" "$PROFILE_PROC_PATTERNS" "$PROFILE_NAME" + basic|daemon_lifecycle|service_rebind) + if ! module_reload_stop_mask_kill_services \ + "$quiesce_services" \ + "$quiesce_proc_patterns" \ + 20 \ + "$PROFILE_NAME"; then + module_reload_log_service_process_summary \ + "$quiesce_services" \ + "$quiesce_proc_patterns" \ + "$PROFILE_NAME" log_error "[$PROFILE_NAME] quiesce: services/processes did not fully stop" return 1 fi + MRV_PROFILE_QUIESCED="1" ;; *) log_warn "[$PROFILE_NAME] unknown mode '$PROFILE_SELECTED_MODE', continuing without quiesce actions" ;; esac - + return 0 } +# Dispatch optional post-unload hook. module_reload_profile_post_unload() { iter_dir="$1" : "${iter_dir:=}" @@ -699,41 +1227,54 @@ module_reload_profile_post_unload() { return 0 } +# Dispatch optional post-load hook or generic daemon restart. module_reload_profile_post_load() { iter_dir="$1" - svc_log="$iter_dir/post_load_services.log" : "${iter_dir:=}" - + svc_log="$iter_dir/post_load_services.log" + if mrv_profile_override_defined profile_post_load; then profile_post_load "$iter_dir" return $? fi - - if ! command -v systemctl >/dev/null 2>&1; then - return 0 - fi - + case "$PROFILE_SELECTED_MODE" in basic) + # Do not restore quiesced services after every basic-mode iteration. + # + # Restoring here causes repeated start/stop cycles for services such as + # pipewire, wireplumber, NetworkManager, and wpa_supplicant. For audio, + # repeated pipewire-pulse stop/start can stall the test. + # + # Services are restored once in module_reload_profile_finalize() or from + # the run.sh cleanup trap if the test exits early. + module_reload_dump_service_status "$PROFILE_QUIESCE_SERVICES" "$svc_log" return 0 ;; daemon_lifecycle|service_rebind) + if ! command -v systemctl >/dev/null 2>&1; then + return 0 + fi + if ! module_reload_start_services "$PROFILE_SERVICES" 15 "$PROFILE_NAME"; then module_reload_log_service_process_summary "$PROFILE_SERVICES" "$PROFILE_PROC_PATTERNS" "$PROFILE_NAME" log_error "[$PROFILE_NAME] post-load: services failed to become active after reload" + module_reload_restore_recorded_services "$PROFILE_NAME" return 1 fi - + module_reload_dump_service_status "$PROFILE_SERVICES" "$svc_log" + module_reload_restore_recorded_services "$PROFILE_NAME" ;; *) log_warn "[$PROFILE_NAME] unknown mode '$PROFILE_SELECTED_MODE', continuing without post-load actions" ;; esac - + return 0 } +# Dispatch optional smoke hook. module_reload_profile_smoke() { iter_dir="$1" : "${iter_dir:=}" @@ -746,27 +1287,33 @@ module_reload_profile_smoke() { return 0 } +# Dispatch optional finalize hook or restore services that were managed. module_reload_profile_finalize() { profile_root="$1" : "${profile_root:=}" - + if mrv_profile_override_defined profile_finalize; then profile_finalize "$profile_root" - return $? + profile_finalize_rc=$? + module_reload_restore_recorded_services "$PROFILE_NAME" + return "$profile_finalize_rc" fi - + + module_reload_restore_recorded_services "$PROFILE_NAME" + if ! command -v systemctl >/dev/null 2>&1; then return 0 fi - + if ! module_reload_restore_services "$PROFILE_SERVICES" 15 "$PROFILE_NAME"; then log_error "[$PROFILE_NAME] finalize: failed to restore services" return 1 fi - + return 0 } +# Validate the profile after it is sourced and before iterations run. mrv_profile_check() { requested_mode="$1" @@ -775,6 +1322,10 @@ mrv_profile_check() { return 2 fi + if mrv_should_skip_for_loaded_conflict_modules; then + return 2 + fi + if [ "${MODULE_RELOAD_SUPPORTED:-yes}" != "yes" ]; then MRV_PROFILE_REASON="profile marks module as non-reloadable" return 2 @@ -804,6 +1355,7 @@ mrv_profile_check() { required="${PROFILE_REQUIRED_CMDS:-}" if [ -n "$required" ]; then + # Intentional word splitting: required commands are profile data. # shellcheck disable=SC2086 set -- $required for req in "$@"; do @@ -821,22 +1373,68 @@ mrv_profile_check() { return 0 } +# Validate that a list of modules is present or absent. +mrv_validate_module_list_state() { + want="$1" + modules="$2" + + [ -n "$modules" ] || return 0 + + for mod in $modules; do + [ -n "$mod" ] || continue + + case "$want" in + absent) + if mrv_module_loaded "$mod"; then + log_fail "[$PROFILE_NAME] expected module absent after unload, but still loaded: $mod" + return 1 + fi + ;; + present) + if ! mrv_module_loaded "$mod"; then + log_fail "[$PROFILE_NAME] expected module present after load, but missing: $mod" + return 1 + fi + ;; + *) + log_error "[$PROFILE_NAME] invalid module state request: $want" + return 1 + ;; + esac + done + + return 0 +} + +# Validate module state after unload completes. mrv_post_unload_validate() { if ! mrv_wait_module_state absent "$MODULE_NAME" "$TIMEOUT_SETTLE"; then log_fail "[$PROFILE_NAME] module still present after unload settle timeout" return 1 fi + + if ! mrv_validate_module_list_state absent "$PROFILE_EXPECT_ABSENT_AFTER_UNLOAD"; then + return 1 + fi + return 0 } +# Validate module state after load completes. mrv_post_load_validate() { if ! mrv_wait_module_state present "$MODULE_NAME" "$TIMEOUT_SETTLE"; then log_fail "[$PROFILE_NAME] module did not reappear after load settle timeout" return 1 fi + + if ! mrv_validate_module_list_state present "$PROFILE_EXPECT_PRESENT_AFTER_LOAD"; then + return 1 + fi + return 0 } +# Execute one unload/reload iteration for the active profile. mrv_run_iteration() { iter="$1" iter_dir="$RESULT_ROOT/$PROFILE_NAME/iter_$(printf '%02d' "$iter")" @@ -967,6 +1565,7 @@ mrv_run_iteration() { return 0 } +# Run one profile in a subshell so profile variables and hooks do not leak. mrv_run_one_profile() ( profile_file="$1" requested_mode="$2" @@ -1021,6 +1620,7 @@ mrv_run_one_profile() ( exit 0 ) +# Resolve explicit module, profile list, enabled list, or all profile files. mrv_resolve_profiles() { target_module="$1" profile_dir="$2" @@ -1059,3 +1659,4 @@ mrv_resolve_profiles() { return 0 } + From b0c898caf583065ad74056787028626716cceb13 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Sat, 27 Jun 2026 23:08:08 +0530 Subject: [PATCH 2/5] Module_Reload_Validation: update run.sh profile orchestration Update run.sh to keep module reload execution generic and profile driven. Add support for explicit profile selection, profile-list execution, timeout arguments, sysrq hang-dump control, result summary generation, and repo-standard execution flow. This keeps run.sh as a thin orchestration layer while lib_module_reload.sh and profiles own the reload behavior. Signed-off-by: Srikanth Muppandam --- .../Baseport/Module_Reload_Validation/run.sh | 61 ++++++++++++++++--- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/run.sh b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/run.sh index efba6b83a..d914d5ef1 100755 --- a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/run.sh +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/run.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause-Clear +# SPDX-License-Identifier: BSD-3-Clause SCRIPT_DIR="$( cd "$(dirname "$0")" || exit 1 @@ -60,7 +60,7 @@ Usage: $0 [options] --mode MODE Profile mode override --profile-dir PATH Override profile directory --profile-list FILE Override enabled profile list file - --enable-sysrq-hang-dump Enable sysrq dump on timeout paths + --enable-sysrq-hang-dump [0|1] Enable sysrq dump on timeout paths, optional value accepted --disable-sysrq-hang-dump Disable sysrq dump on timeout paths --verbose Enable verbose shell logging --help|-h Show this help @@ -69,17 +69,39 @@ EOF # shellcheck disable=SC2317 # invoked via trap cleanup() { + if command -v module_reload_restore_recorded_services >/dev/null 2>&1; then + module_reload_restore_recorded_services "$TESTNAME-cleanup" >/dev/null 2>&1 || true + fi + if [ -n "$PROFILE_TMP_LIST" ]; then rm -f "$PROFILE_TMP_LIST" 2>/dev/null fi } - + +parse_sysrq_value() { + value="$1" + + case "$value" in + 1|yes|true|enable|enabled|on) + ENABLE_SYSRQ_HANG_DUMP=1 + ;; + 0|no|false|disable|disabled|off) + ENABLE_SYSRQ_HANG_DUMP=0 + ;; + *) + log_error "Invalid sysrq hang dump value: $value" + usage + exit 1 + ;; + esac +} + trap 'cleanup' EXIT INT TERM while [ $# -gt 0 ]; do case "$1" in --module) - if [ $# -lt 2 ] || [ -z "$2" ]; then + if [ $# -lt 2 ]; then log_error "Missing value for --module" usage exit 1 @@ -124,7 +146,7 @@ while [ $# -gt 0 ]; do shift 2 ;; --mode) - if [ $# -lt 2 ] || [ -z "$2" ]; then + if [ $# -lt 2 ]; then log_error "Missing value for --mode" usage exit 1 @@ -142,7 +164,7 @@ while [ $# -gt 0 ]; do shift 2 ;; --profile-list) - if [ $# -lt 2 ] || [ -z "$2" ]; then + if [ $# -lt 2 ]; then log_error "Missing value for --profile-list" usage exit 1 @@ -151,8 +173,21 @@ while [ $# -gt 0 ]; do shift 2 ;; --enable-sysrq-hang-dump) - ENABLE_SYSRQ_HANG_DUMP=1 - shift + if [ $# -ge 2 ]; then + case "$2" in + --*) + ENABLE_SYSRQ_HANG_DUMP=1 + shift + ;; + *) + parse_sysrq_value "$2" + shift 2 + ;; + esac + else + ENABLE_SYSRQ_HANG_DUMP=1 + shift + fi ;; --disable-sysrq-hang-dump) ENABLE_SYSRQ_HANG_DUMP=0 @@ -174,6 +209,10 @@ while [ $# -gt 0 ]; do esac done +if [ -z "$PROFILE_LIST_FILE" ]; then + PROFILE_LIST_FILE="$PROFILE_LIST_DEFAULT" +fi + if [ "$VERBOSE" -eq 1 ] 2>/dev/null; then set -x fi @@ -190,6 +229,10 @@ esac case "$TIMEOUT_SETTLE" in ''|*[!0-9]*) log_error "Invalid --timeout-settle: $TIMEOUT_SETTLE"; exit 1 ;; esac +case "$ENABLE_SYSRQ_HANG_DUMP" in + 0|1) ;; + *) log_error "Invalid sysrq hang dump setting: $ENABLE_SYSRQ_HANG_DUMP"; exit 1 ;; +esac test_path="$(find_test_case_by_name "$TESTNAME" 2>/dev/null || echo "$SCRIPT_DIR")" if ! cd "$test_path"; then @@ -211,7 +254,7 @@ else log_info "Platform Details: unknown" fi -log_info "Args: module='${TARGET_MODULE:-all-enabled}' iterations=$ITERATIONS unload_timeout=$TIMEOUT_UNLOAD load_timeout=$TIMEOUT_LOAD settle_timeout=$TIMEOUT_SETTLE mode='${PROFILE_MODE:-profile-default}' sysrq_dump=$ENABLE_SYSRQ_HANG_DUMP" +log_info "Args: module='${TARGET_MODULE:-all-enabled}' profile_list='${PROFILE_LIST_FILE}' iterations=$ITERATIONS unload_timeout=$TIMEOUT_UNLOAD load_timeout=$TIMEOUT_LOAD settle_timeout=$TIMEOUT_SETTLE mode='${PROFILE_MODE:-profile-default}' sysrq_dump=$ENABLE_SYSRQ_HANG_DUMP" if [ "$ENABLE_SYSRQ_HANG_DUMP" -eq 1 ] 2>/dev/null; then log_info "Sysrq hang dump policy: enabled on timeout paths only" From c6d4e39472fc9c86f6f51d1853baf09d91732a0c Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Sat, 27 Jun 2026 23:09:02 +0530 Subject: [PATCH 3/5] Module_Reload_Validation: add base profiles and profile lists Add and refine base-image module reload profiles for FastRPC, Ethernet, Wi-Fi, crypto, secure comms, MVM, Venus, Iris, TC956x Ethernet, and Qualcomm SoundWire/ASoC. Add profile list files to support grouped execution of base and overlay module reload coverage. Keep enabled.list conservative for default CI while allowing teams to explicitly run broader base or overlay validation through --profile-list. Signed-off-by: Srikanth Muppandam --- .../profiles/ath11k_ahb.profile | 35 +++++++++++++++ .../profiles/ath11k_pci.profile | 25 +++++++++++ .../profiles/ath12k_pci.profile | 21 +++++++++ .../profiles/audioreach.profile | 19 ++++++++ .../profiles/base.list | 14 ++++++ .../profiles/camera.profile | 45 +++++++++++++++++++ .../profiles/dwmac_qcom_eth.profile | 17 +++++++ .../profiles/fastrpc.profile | 33 ++++++++++---- .../profiles/iris.profile | 29 ++++++++++++ .../profiles/msm.profile | 24 ++++++++++ .../profiles/msm_drm.profile | 19 ++++++++ .../profiles/msm_kgsl.profile | 26 +++++++++++ .../profiles/mvm.profile | 18 ++++++++ .../profiles/overlay.list | 4 ++ .../profiles/qcedev_mod_dlkm.profile | 17 +++++++ .../profiles/qcom_iris.profile | 18 ++++++++ .../profiles/qcrypto_msm_dlkm.profile | 18 ++++++++ .../profiles/qrng_dlkm.profile | 18 ++++++++ .../profiles/snd_soc_qcom_sdw.profile | 32 +++++++++++++ .../profiles/spcom.profile | 19 ++++++++ .../profiles/tc956x_pcie_eth.profile | 18 ++++++++ .../profiles/venus_core.profile | 17 +++++++ 22 files changed, 478 insertions(+), 8 deletions(-) create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath11k_ahb.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath11k_pci.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath12k_pci.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/audioreach.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/base.list create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/camera.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/dwmac_qcom_eth.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/iris.profile create mode 100644 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm_drm.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm_kgsl.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/mvm.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/overlay.list create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcedev_mod_dlkm.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcom_iris.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcrypto_msm_dlkm.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qrng_dlkm.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/snd_soc_qcom_sdw.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/spcom.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/tc956x_pcie_eth.profile create mode 100755 Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/venus_core.profile diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath11k_ahb.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath11k_ahb.profile new file mode 100755 index 000000000..6c1e1d4cd --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath11k_ahb.profile @@ -0,0 +1,35 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="ath11k_ahb" +PROFILE_DESCRIPTION="ath11k AHB Wi-Fi module reload validation" +MODULE_NAME="ath11k_ahb" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="basic" +PROFILE_QUIESCE_ONCE="yes" + +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed grep readlink sort awk tr" + +PROFILE_SKIP_IF_MODULES_LOADED="ath11k_pci ath12k_pci" +PROFILE_UNLOAD_STACK="ath11k_ahb ath11k mac80211 cfg80211" + +PROFILE_QUIESCE_SERVICES="wpa_supplicant.service NetworkManager.service systemd-networkd.service" +PROFILE_PROC_PATTERNS="wpa_supplicant NetworkManager iwd" +PROFILE_QUIESCE_PROC_PATTERNS="$PROFILE_PROC_PATTERNS" + +PROFILE_DEVICE_PATTERNS="/sys/class/net/wlan* /sys/class/ieee80211/*" +PROFILE_SYSFS_PATTERNS="/sys/module/ath11k_ahb /sys/module/ath11k /sys/module/mac80211 /sys/module/cfg80211" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="ath11k_ahb ath11k" +PROFILE_EXPECT_PRESENT_AFTER_LOAD="ath11k_ahb" + +module_reload_profile_setup_stack + +profile_quiesce() { + module_reload_profile_quiesce_resources "$PROFILE_NAME" "$1" 20 +} + +profile_smoke() { + module_reload_profile_smoke_modules_present "$PROFILE_NAME" "$PROFILE_EXPECT_PRESENT_AFTER_LOAD" +} diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath11k_pci.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath11k_pci.profile new file mode 100755 index 000000000..6143d00aa --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath11k_pci.profile @@ -0,0 +1,25 @@ +#!/bin/sh +#SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="ath11k_pci" +PROFILE_DESCRIPTION="ath11k PCI Wi-Fi module reload validation" +MODULE_NAME="ath11k_pci" + +PROFILE_SKIP_IF_MODULES_LOADED="ath11k_ahb ath12k_pci" +PROFILE_UNLOAD_STACK="ath11k_pci ath11k mac80211 cfg80211" +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="ath11k_pci ath11k" + +PROFILE_MODE_DEFAULT="basic" +PROFILE_QUIESCE_ONCE="yes" +PROFILE_QUIESCE_SERVICES="wpa_supplicant.service NetworkManager.service systemd-networkd.service" +PROFILE_PROC_PATTERNS="wpa_supplicant NetworkManager iwd" +PROFILE_QUIESCE_PROC_PATTERNS="$PROFILE_PROC_PATTERNS" + +PROFILE_DEVICE_PATTERNS="/sys/class/net/wlan* /sys/class/ieee80211/*" +PROFILE_SYSFS_PATTERNS="/sys/module/ath11k_pci /sys/module/ath11k /sys/module/mac80211 /sys/module/cfg80211" + +module_reload_profile_setup_stack + +profile_quiesce() { + module_reload_profile_quiesce_resources "$PROFILE_NAME" "$1" 20 +} diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath12k_pci.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath12k_pci.profile new file mode 100755 index 000000000..c3b91064c --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/ath12k_pci.profile @@ -0,0 +1,21 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="ath12k_pci" +PROFILE_DESCRIPTION="ath12k PCI Wi-Fi module reload validation" +MODULE_NAME="ath12k_pci" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="daemon_lifecycle" + +PROFILE_QUIESCE_ONCE="yes" +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" +PROFILE_SERVICES="wpa_supplicant.service NetworkManager.service systemd-networkd.service" +PROFILE_PROC_PATTERNS="wpa_supplicant NetworkManager iwd" + +MODULE_UNLOAD_CMD="modprobe -r ath12k_pci ath12k mac80211 cfg80211" +MODULE_LOAD_CMD="modprobe ath12k_pci" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="ath12k_pci ath12k" +PROFILE_DEVICE_PATTERNS="/sys/class/net/wlan* /sys/class/ieee80211/*" +PROFILE_SYSFS_PATTERNS="/sys/module/ath12k_pci /sys/module/ath12k /sys/module/mac80211 /sys/module/cfg80211" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/audioreach.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/audioreach.profile new file mode 100755 index 000000000..a1a9e3727 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/audioreach.profile @@ -0,0 +1,19 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="audioreach" +PROFILE_DESCRIPTION="AudioReach downstream audio overlay module reload validation" +MODULE_NAME="snd_soc_qdsp6" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="daemon_lifecycle" + +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" +PROFILE_SERVICES="audioserver.service pipewire.service pulseaudio.service" +PROFILE_PROC_PATTERNS="audioserver pipewire pulseaudio" +MODULE_UNLOAD_CMD="modprobe -r snd_soc_qdsp6 q6asm q6adm q6afe apr" +MODULE_LOAD_CMD="modprobe snd_soc_qdsp6" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="snd_soc_qdsp6" +PROFILE_DEVICE_PATTERNS="/dev/snd/*" +PROFILE_SYSFS_PATTERNS="/sys/module/snd_soc_qdsp6 /sys/module/q6asm /sys/module/q6adm /sys/module/q6afe /sys/module/apr" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/base.list b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/base.list new file mode 100755 index 000000000..0325b25d0 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/base.list @@ -0,0 +1,14 @@ +fastrpc +dwmac_qcom_eth +tc956x_pcie_eth +ath11k_pci +ath11k_ahb +ath12k_pci +qcedev_mod_dlkm +qcrypto_msm_dlkm +qrng_dlkm +spcom +mvm +venus_core +qcom_iris +snd_soc_qcom_sdw diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/camera.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/camera.profile new file mode 100755 index 000000000..84f16701b --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/camera.profile @@ -0,0 +1,45 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="camera" +PROFILE_DESCRIPTION="CAMX camera KMD overlay reload validation" + +CAMERA_MODULE_NAME="" +for cname in camera camera_kmd camx_kmd; do + if mrv_module_loaded "$cname" || modinfo "$cname" >/dev/null 2>&1; then + CAMERA_MODULE_NAME="$cname" + break + fi +done + +if [ -n "$CAMERA_MODULE_NAME" ]; then + MODULE_NAME="$CAMERA_MODULE_NAME" + MODULE_RELOAD_SUPPORTED="yes" + MODULE_UNLOAD_CMD="modprobe -r $CAMERA_MODULE_NAME camss" + MODULE_LOAD_CMD="modprobe $CAMERA_MODULE_NAME" + PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="$CAMERA_MODULE_NAME" +else + MODULE_NAME="camera" + MODULE_RELOAD_SUPPORTED="no" +fi + +PROFILE_MODE_DEFAULT="daemon_lifecycle" +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" +PROFILE_SERVICES="qmmf-server.service qmmf-recorder.service" +PROFILE_PROC_PATTERNS="qmmf-server qmmf-recorder gst-launch" +PROFILE_DEVICE_PATTERNS="/dev/video* /dev/media*" +PROFILE_SYSFS_PATTERNS="/sys/module/camera /sys/module/camera_kmd /sys/module/camx_kmd /sys/module/camss" + +profile_quiesce() { + iter_dir="$1" + : "${iter_dir:=}" + + module_reload_stop_mask_kill_services "$PROFILE_SERVICES" "$PROFILE_PROC_PATTERNS" 20 "$PROFILE_NAME" || return 1 + + if command -v pkill >/dev/null 2>&1; then + pkill -f "gst-launch.*camera" 2>/dev/null || true + fi + + sleep 2 + return 0 +} diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/dwmac_qcom_eth.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/dwmac_qcom_eth.profile new file mode 100755 index 000000000..9fc7a0a6b --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/dwmac_qcom_eth.profile @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="dwmac_qcom_eth" +PROFILE_DESCRIPTION="Qualcomm DWMAC/STMMAC Ethernet module reload validation" +MODULE_NAME="dwmac_qcom_eth" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="basic" + +PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed" +MODULE_UNLOAD_CMD="modprobe -r dwmac_qcom_eth stmmac_platform stmmac" +MODULE_LOAD_CMD="modprobe dwmac_qcom_eth" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="dwmac_qcom_eth stmmac_platform stmmac" +PROFILE_DEVICE_PATTERNS="/sys/class/net/*" +PROFILE_SYSFS_PATTERNS="/sys/module/dwmac_qcom_eth /sys/module/stmmac_platform /sys/module/stmmac" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/fastrpc.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/fastrpc.profile index 91efdcc46..8f5f66bcd 100755 --- a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/fastrpc.profile +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/fastrpc.profile @@ -1,16 +1,33 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause-Clear +# SPDX-License-Identifier: BSD-3-Clause PROFILE_NAME="fastrpc" PROFILE_DESCRIPTION="FastRPC module reload validation" MODULE_NAME="fastrpc" -MODULE_RELOAD_SUPPORTED="yes" -PROFILE_MODE_DEFAULT="daemon_lifecycle" +PROFILE_MODE_DEFAULT="basic" +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed grep readlink sort awk tr" -PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" -PROFILE_SERVICES="adsprpcd.service cdsprpcd.service" -PROFILE_PROC_PATTERNS="/usr/bin/adsprpcd /usr/bin/cdsprpcd" -PROFILE_DEVICE_PATTERNS="/dev/fastrpc-* /dev/*dsp*" -PROFILE_SYSFS_PATTERNS="/sys/module/fastrpc /sys/class/remoteproc/*" +PROFILE_QUIESCE_ONCE="yes" +PROFILE_QUIESCE_SERVICES="adsprpcd.service cdsprpcd.service" +PROFILE_PROC_PATTERNS="adsprpcd cdsprpcd fastrpc_shell" +PROFILE_QUIESCE_PROC_PATTERNS="$PROFILE_PROC_PATTERNS" + +PROFILE_DEVICE_PATTERNS="/dev/fastrpc-* /dev/adsprpc-* /dev/cdsprpc-* /dev/*dsp*" +PROFILE_QUIESCE_DEVICE_PATTERNS="$PROFILE_DEVICE_PATTERNS" + +PROFILE_SYSFS_PATTERNS="/sys/module/fastrpc /sys/class/remoteproc/* /sys/kernel/debug/fastrpc* /sys/kernel/debug/adsprpc*" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="fastrpc" +PROFILE_EXPECT_PRESENT_AFTER_LOAD="fastrpc" + +module_reload_profile_setup_stack + +profile_quiesce() { + module_reload_profile_quiesce_resources "$PROFILE_NAME" "$1" 20 +} + +profile_smoke() { + module_reload_profile_smoke_modules_present "$PROFILE_NAME" "$PROFILE_EXPECT_PRESENT_AFTER_LOAD" +} diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/iris.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/iris.profile new file mode 100755 index 000000000..3cd7057ac --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/iris.profile @@ -0,0 +1,29 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="iris" +PROFILE_DESCRIPTION="Downstream Iris video overlay module reload validation" + +IRIS_MODULE_NAME="" +for vname in iris iris_vpu; do + if mrv_module_loaded "$vname" || modinfo "$vname" >/dev/null 2>&1; then + IRIS_MODULE_NAME="$vname" + break + fi +done + +if [ -n "$IRIS_MODULE_NAME" ]; then + MODULE_NAME="$IRIS_MODULE_NAME" + MODULE_RELOAD_SUPPORTED="yes" + MODULE_UNLOAD_CMD="modprobe -r $IRIS_MODULE_NAME" + MODULE_LOAD_CMD="modprobe $IRIS_MODULE_NAME" + PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="$IRIS_MODULE_NAME" +else + MODULE_NAME="iris" + MODULE_RELOAD_SUPPORTED="no" +fi + +PROFILE_MODE_DEFAULT="basic" +PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed" +PROFILE_DEVICE_PATTERNS="/dev/video* /dev/media*" +PROFILE_SYSFS_PATTERNS="/sys/module/iris /sys/module/iris_vpu" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm.profile new file mode 100644 index 000000000..b72943704 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm.profile @@ -0,0 +1,24 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +PROFILE_NAME="msm" +PROFILE_DESCRIPTION="Qualcomm MSM DRM / Adreno GPU driver reload validation" +MODULE_NAME="msm" + +PROFILE_MODE_DEFAULT="basic" +PROFILE_REQUIRED_CMDS="modprobe rmmod grep ps sed" + +PROFILE_QUIESCE_ONCE="yes" +PROFILE_QUIESCE_SERVICES="weston.service display-manager.service" +PROFILE_QUIESCE_PROC_PATTERNS="weston Xorg Xwayland kmscube modetest glmark2 glmark2-es2 glmark2-es2-drm es2gears glxgears vkmark" + +PROFILE_DEVICE_PATTERNS="/dev/dri/* /dev/fb*" +PROFILE_QUIESCE_DEVICE_PATTERNS="$PROFILE_DEVICE_PATTERNS" + +PROFILE_SYSFS_PATTERNS="/sys/module/msm /sys/class/drm /sys/kernel/debug/dri/*" + +MODULE_UNLOAD_CMD="modprobe -r msm" +MODULE_LOAD_CMD="modprobe msm" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="msm" +PROFILE_EXPECT_PRESENT_AFTER_LOAD="msm" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm_drm.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm_drm.profile new file mode 100755 index 000000000..5a9d0fedd --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm_drm.profile @@ -0,0 +1,19 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="msm_drm" +PROFILE_DESCRIPTION="Downstream MSM DRM display overlay module reload validation" +MODULE_NAME="msm_drm" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="daemon_lifecycle" + +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" +PROFILE_SERVICES="weston.service display-manager.service" +PROFILE_PROC_PATTERNS="weston kmscube glmark2" +MODULE_UNLOAD_CMD="modprobe -r msm_drm" +MODULE_LOAD_CMD="modprobe msm_drm" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="msm_drm" +PROFILE_DEVICE_PATTERNS="/dev/dri/*" +PROFILE_SYSFS_PATTERNS="/sys/module/msm_drm /sys/class/drm/*" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm_kgsl.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm_kgsl.profile new file mode 100755 index 000000000..0c014c5b9 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/msm_kgsl.profile @@ -0,0 +1,26 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +PROFILE_NAME="msm_kgsl" +PROFILE_DESCRIPTION="Legacy Qualcomm KGSL GPU driver reload validation" +MODULE_NAME="msm_kgsl" + +PROFILE_MODE_DEFAULT="basic" +PROFILE_REQUIRED_CMDS="modprobe rmmod grep ps sed" + +if ! mrv_module_available "msm_kgsl"; then + MODULE_RELOAD_SUPPORTED="no" + MODULE_RELOAD_UNSUPPORTED_REASON="legacy KGSL driver msm_kgsl not present; modern Adreno platforms use MSM DRM driver msm" +else + PROFILE_QUIESCE_SERVICES="weston.service display-manager.service" + PROFILE_QUIESCE_PROC_PATTERNS="weston Xorg Xwayland glmark2 kmscube modetest es2gears glxgears vkmark" + + PROFILE_DEVICE_PATTERNS="/dev/kgsl-3d0 /dev/dri/*" + PROFILE_SYSFS_PATTERNS="/sys/module/msm_kgsl /sys/class/kgsl/kgsl-3d0" + + PROFILE_UNLOAD_STACK="governor_msm_adreno_tz governor_gpubw_mon msm_kgsl" + PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="msm_kgsl" + PROFILE_EXPECT_PRESENT_AFTER_LOAD="msm_kgsl" + + module_reload_profile_setup_stack +fi diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/mvm.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/mvm.profile new file mode 100755 index 000000000..03b5be3ea --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/mvm.profile @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="mvm" +PROFILE_DESCRIPTION="MVM DLKM reload validation" +MODULE_NAME="mvm" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="daemon_lifecycle" + +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" +PROFILE_SERVICES="mvm.service" +PROFILE_PROC_PATTERNS="mvm" +MODULE_UNLOAD_CMD="modprobe -r mvm" +MODULE_LOAD_CMD="modprobe mvm" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="mvm" +PROFILE_SYSFS_PATTERNS="/sys/module/mvm" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/overlay.list b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/overlay.list new file mode 100755 index 000000000..1221ceb10 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/overlay.list @@ -0,0 +1,4 @@ +msm +camera +iris +audioreach diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcedev_mod_dlkm.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcedev_mod_dlkm.profile new file mode 100755 index 000000000..5b8678c5a --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcedev_mod_dlkm.profile @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="qcedev_mod_dlkm" +PROFILE_DESCRIPTION="QCEDEV crypto DLKM reload validation" +MODULE_NAME="qcedev_mod_dlkm" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="basic" + +PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed" +MODULE_UNLOAD_CMD="modprobe -r qcedev_mod_dlkm qce50_dlkm" +MODULE_LOAD_CMD="modprobe qcedev_mod_dlkm" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="qcedev_mod_dlkm qce50_dlkm" +PROFILE_DEVICE_PATTERNS="/dev/qce* /dev/qcedev*" +PROFILE_SYSFS_PATTERNS="/sys/module/qcedev_mod_dlkm /sys/module/qce50_dlkm" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcom_iris.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcom_iris.profile new file mode 100755 index 000000000..ef204b3da --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcom_iris.profile @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="qcom_iris" +PROFILE_DESCRIPTION="Qualcomm Iris video module reload validation" +MODULE_NAME="qcom_iris" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="basic" + +PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed" + +MODULE_UNLOAD_CMD="modprobe -r qcom_iris" +MODULE_LOAD_CMD="modprobe qcom_iris" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="qcom_iris" +PROFILE_DEVICE_PATTERNS="/dev/video* /dev/media*" +PROFILE_SYSFS_PATTERNS="/sys/module/qcom_iris" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcrypto_msm_dlkm.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcrypto_msm_dlkm.profile new file mode 100755 index 000000000..3ca74bc23 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qcrypto_msm_dlkm.profile @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="qcrypto_msm_dlkm" +PROFILE_DESCRIPTION="QCrypto MSM DLKM reload validation" +MODULE_NAME="qcrypto_msm_dlkm" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="daemon_lifecycle" + +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" +PROFILE_SERVICES="qcrypto.service" +PROFILE_PROC_PATTERNS="qcrypto" +MODULE_UNLOAD_CMD="modprobe -r qcrypto_msm_dlkm" +MODULE_LOAD_CMD="modprobe qcrypto_msm_dlkm" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="qcrypto_msm_dlkm" +PROFILE_SYSFS_PATTERNS="/sys/module/qcrypto_msm_dlkm" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qrng_dlkm.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qrng_dlkm.profile new file mode 100755 index 000000000..8aae7f13f --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/qrng_dlkm.profile @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="qrng_dlkm" +PROFILE_DESCRIPTION="QRNG DLKM reload validation" +MODULE_NAME="qrng_dlkm" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="daemon_lifecycle" + +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" +PROFILE_SERVICES="qrng.service" +PROFILE_PROC_PATTERNS="qrng" +MODULE_UNLOAD_CMD="modprobe -r qrng_dlkm" +MODULE_LOAD_CMD="modprobe qrng_dlkm" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="qrng_dlkm" +PROFILE_SYSFS_PATTERNS="/sys/module/qrng_dlkm" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/snd_soc_qcom_sdw.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/snd_soc_qcom_sdw.profile new file mode 100755 index 000000000..ba9d5537b --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/snd_soc_qcom_sdw.profile @@ -0,0 +1,32 @@ +#!/bin/sh +#SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="snd_soc_qcom_sdw" +PROFILE_DESCRIPTION="Qualcomm ASoC/SoundWire stack reload validation" +MODULE_NAME="snd_soc_qcom_sdw" + +PROFILE_MODE_DEFAULT="basic" +PROFILE_QUIESCE_ONCE="yes" +PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed grep readlink sort awk tr" + +PROFILE_TOP_MODULE_CANDIDATES="snd_soc_sc8280xp" + +PROFILE_QUIESCE_SERVICES="pipewire.service wireplumber.service pulseaudio.service" +PROFILE_PROC_PATTERNS="pipewire-pulse pipewire wireplumber pulseaudio aplay arecord speaker-test pw-play pw-record gst-launch" +PROFILE_QUIESCE_PROC_PATTERNS="$PROFILE_PROC_PATTERNS" + +PROFILE_DEVICE_PATTERNS="/dev/snd/*" +PROFILE_QUIESCE_DEVICE_PATTERNS="$PROFILE_DEVICE_PATTERNS" + +PROFILE_SYSFS_PATTERNS="/sys/module/snd_soc_sc8280xp /sys/module/snd_soc_qcom_sdw /sys/module/soundwire_qcom /sys/module/snd_soc_wsa883x /sys/bus/soundwire/devices/*" + +module_reload_profile_setup_stack + +profile_quiesce() { + module_reload_profile_quiesce_resources "$PROFILE_NAME" "$1" 20 +} + +profile_smoke() { + module_reload_profile_smoke_modules_present "$PROFILE_NAME" "$PROFILE_EXPECT_PRESENT_AFTER_LOAD" +} + diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/spcom.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/spcom.profile new file mode 100755 index 000000000..d02ad6c22 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/spcom.profile @@ -0,0 +1,19 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="spcom" +PROFILE_DESCRIPTION="Secure Processor communication module reload validation" +MODULE_NAME="spcom" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="daemon_lifecycle" + +PROFILE_REQUIRED_CMDS="modprobe rmmod systemctl ps sed" +PROFILE_SERVICES="spdaemon.service qseecomd.service keymaster-4-0.service" +PROFILE_PROC_PATTERNS="spdaemon qseecomd keymaster" +MODULE_UNLOAD_CMD="modprobe -r spcom" +MODULE_LOAD_CMD="modprobe spcom" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="spcom" +PROFILE_DEVICE_PATTERNS="/dev/spcom* /dev/qseecom*" +PROFILE_SYSFS_PATTERNS="/sys/module/spcom" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/tc956x_pcie_eth.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/tc956x_pcie_eth.profile new file mode 100755 index 000000000..660bbdf35 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/tc956x_pcie_eth.profile @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="tc956x_pcie_eth" +PROFILE_DESCRIPTION="TC956x PCIe Ethernet module reload validation" +MODULE_NAME="tc956x_pcie_eth" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="basic" + +PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed" + +MODULE_UNLOAD_CMD="modprobe -r tc956x_pcie_eth" +MODULE_LOAD_CMD="modprobe tc956x_pcie_eth" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="tc956x_pcie_eth" +PROFILE_DEVICE_PATTERNS="/sys/class/net/*" +PROFILE_SYSFS_PATTERNS="/sys/module/tc956x_pcie_eth" diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/venus_core.profile b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/venus_core.profile new file mode 100755 index 000000000..c40f4c7c7 --- /dev/null +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/venus_core.profile @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause + +PROFILE_NAME="venus_core" +PROFILE_DESCRIPTION="Upstream Venus video module reload validation" +MODULE_NAME="venus_core" + +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="basic" + +PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed" +MODULE_UNLOAD_CMD="modprobe -r venus_enc venus_dec venus_core" +MODULE_LOAD_CMD="modprobe venus_core" + +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="venus_enc venus_dec venus_core" +PROFILE_DEVICE_PATTERNS="/dev/video* /dev/media*" +PROFILE_SYSFS_PATTERNS="/sys/module/venus_core /sys/module/venus_enc /sys/module/venus_dec" From e670ab086c8ccb4a733013775b231f5635ac97fa Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Sat, 27 Jun 2026 23:09:35 +0530 Subject: [PATCH 4/5] Module_Reload_Validation: align LAVA definition with profile parameters Update the LAVA test definition to call the suite using repo-standard run steps and parameterized profile selection. Support single-profile execution through PROFILE and grouped execution through PROFILE_LIST without requiring one YAML file per module. Signed-off-by: Srikanth Muppandam --- .../Module_Reload_Validation/Module_Reload_Validation.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.yaml b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.yaml index 4590b8c04..a73187409 100755 --- a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.yaml +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.yaml @@ -3,7 +3,7 @@ metadata: format: "Lava-Test Test Definition 1.0" description: "Generic profiled kernel module unload/reload regression validation" maintainer: - - Srikanth kumar + - Srikanth Kumar os: - linux scope: @@ -11,6 +11,7 @@ metadata: params: PROFILE: "" + PROFILE_LIST: "" ITERATIONS: "3" MODE: "" TIMEOUT_UNLOAD: "30" @@ -22,7 +23,5 @@ run: steps: - REPO_PATH=$PWD - cd Runner/suites/Kernel/Baseport/Module_Reload_Validation - - SYSRQ_ARG="" - - if [ "${ENABLE_SYSRQ_HANG_DUMP}" = "0" ]; then SYSRQ_ARG="--disable-sysrq-hang-dump"; fi - - ./run.sh --module "${PROFILE}" --iterations "${ITERATIONS}" --mode "${MODE}" --timeout-unload "${TIMEOUT_UNLOAD}" --timeout-load "${TIMEOUT_LOAD}" --timeout-settle "${TIMEOUT_SETTLE}" ${SYSRQ_ARG} || true + - ./run.sh --module "${PROFILE}" --profile-list "${PROFILE_LIST}" --iterations "${ITERATIONS}" --mode "${MODE}" --timeout-unload "${TIMEOUT_UNLOAD}" --timeout-load "${TIMEOUT_LOAD}" --timeout-settle "${TIMEOUT_SETTLE}" --enable-sysrq-hang-dump "${ENABLE_SYSRQ_HANG_DUMP}" || true - $REPO_PATH/Runner/utils/send-to-lava.sh Module_Reload_Validation.res From 6b3d9b115cf2a01756c8e70734539ee0ee3817ab Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Sat, 27 Jun 2026 23:10:02 +0530 Subject: [PATCH 5/5] Module_Reload_Validation: document profile usage and customization Update the README with current framework behavior, CLI usage, LAVA/YAML usage, profile-list execution, team-specific launch examples, profile customization, quiesce/restore behavior, and troubleshooting guidance. Document modern msm.ko DRM handling separately from legacy msm_kgsl and clarify how base and overlay profiles should be selected per platform. Signed-off-by: Srikanth Muppandam --- .../Module_Reload_Validation_README.md | 1219 +++++++++++++++-- 1 file changed, 1094 insertions(+), 125 deletions(-) diff --git a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation_README.md b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation_README.md index 98d7ab90e..a97c4362b 100644 --- a/Runner/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation_README.md +++ b/Runner/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation_README.md @@ -1,18 +1,43 @@ # Module_Reload_Validation ## Overview -`Module_Reload_Validation` is a generic, profile-driven kernel module unload/reload regression suite. + +`Module_Reload_Validation` is a generic, profile-driven kernel module unload/reload regression suite for Qualcomm Linux test coverage. It is intended to catch issues such as: + - module unload hangs, - failed reloads, +- missing or incomplete reloads, - service/device rebind regressions after reload, -- issues that reproduce on the 1st, 2nd, or later reload iteration. +- dependency modules left loaded after unload, +- active users keeping a module busy, +- failures that reproduce only on the 1st, 2nd, or later reload iteration. The suite uses: -- a **generic engine** in `run.sh`, -- shared helper logic in `Runner/utils/lib_module_reload.sh`, -- **module-specific profiles** under `profiles/`. + +- a thin orchestration script in `run.sh`, +- shared generic helper logic in `Runner/utils/lib_module_reload.sh`, +- module-specific profile files under `profiles/`, +- profile list files to group base, overlay, or team-specific coverage. + +The design is intentionally profile-driven so new modules can be added without duplicating module-specific logic in `run.sh`. + +## Recent framework updates + +The current framework has been enhanced to support the following behavior: + +- `run.sh` supports both single-profile execution through `--module` and group execution through `--profile-list`. +- `run.sh` logs the selected profile list in the argument summary. +- `lib_module_reload.sh` contains the common reload engine and generic helper functions. +- Profiles are expected to stay minimal and declarative. +- Complex logic should be moved to reusable library helpers instead of being embedded in each profile. +- Profiles can declare service/process/device quiesce metadata separately from warmup/restore metadata. +- Profiles can use `PROFILE_QUIESCE_ONCE="yes"` to avoid repeatedly stopping the same disruptive services on every iteration. +- The framework can snapshot service state and restore previously active services from the test side after profile execution. +- Profiles can skip when conflicting modules are active, for example `ath11k_pci` can skip when `ath11k_ahb` is the active Wi-Fi transport. +- The Qualcomm SoundWire/ASoC profile is minimal and uses a library helper to discover the top-level holder of `snd_soc_qcom_sdw`. +- Modern Adreno GPU/display validation should treat `msm.ko` as the active upstream DRM driver on RB3Gen2/newer platforms. `msm_kgsl` is legacy KGSL and should not be used for modern RB3Gen2-style DRM stacks. ## Folder layout @@ -20,107 +45,645 @@ The suite uses: Runner/suites/Kernel/Baseport/Module_Reload_Validation/ ├── run.sh ├── Module_Reload_Validation.yaml +├── Module_Reload_Validation_README.md ├── profiles/ │ ├── enabled.list -│ └── fastrpc.profile +│ ├── base.list +│ ├── overlay.list +│ ├── fastrpc.profile +│ ├── dwmac_qcom_eth.profile +│ ├── tc956x_pcie_eth.profile +│ ├── ath11k_pci.profile +│ ├── ath11k_ahb.profile +│ ├── ath12k_pci.profile +│ ├── qcedev_mod_dlkm.profile +│ ├── qcrypto_msm_dlkm.profile +│ ├── qrng_dlkm.profile +│ ├── spcom.profile +│ ├── mvm.profile +│ ├── venus_core.profile +│ ├── qcom_iris.profile +│ ├── snd_soc_qcom_sdw.profile +│ ├── msm.profile +│ ├── msm_kgsl.profile +│ ├── camera.profile +│ ├── iris.profile +│ └── audioreach.profile Runner/utils/ └── lib_module_reload.sh ``` +`msm_kgsl.profile` is legacy KGSL coverage and is expected to skip on modern DRM-based images where `msm.ko` is used instead. + ## Main components ### `run.sh` -Thin orchestration layer that: -- parses CLI arguments, -- resolves the selected profile(s), -- invokes the generic library engine, -- writes `Module_Reload_Validation.res`. - -### `lib_module_reload.sh` -Shared module reload engine that handles: -- module state checks, -- timeout-controlled unload/load execution, -- per-iteration evidence collection, -- timeout-path hang evidence, + +`run.sh` is the orchestration layer. It should remain thin. + +Responsibilities: + +- load `init_env`, `functestlib.sh`, and `lib_module_reload.sh`, +- parse CLI arguments, +- resolve selected profile files, +- run each profile through the generic library engine, +- maintain pass/fail/skip counts, +- write `Module_Reload_Validation.res`, +- leave detailed artifacts under `results/Module_Reload_Validation/`. + +`run.sh` should not contain module-specific reload logic. Module-specific behavior belongs in profile files or reusable helper functions in `lib_module_reload.sh`. + +### `Runner/utils/lib_module_reload.sh` + +`lib_module_reload.sh` contains the shared module reload engine. + +Responsibilities: + +- profile variable reset, +- profile validation, +- module presence and built-in checks, +- loaded-module checks, +- timeout-controlled command execution, +- unload/load validation, +- multi-module stack validation, - profile hook dispatch, -- result handling. +- service/process quiesce, +- best-effort restore of previously active services, +- optional quiesce-once behavior, +- evidence collection, +- timeout/hang evidence collection, +- helper functions for profiles with dynamic topology. + +Examples of reusable helpers: + +- module availability checks, +- holder detection using `/sys/module//holders`, +- holder detection using `/proc/modules`, +- generic top-module selection, +- generic stack setup, +- Qualcomm SoundWire/ASoC stack setup. ### `profiles/*.profile` -Each profile provides module-specific metadata and optional hook logic. - -Example profile fields: -- `PROFILE_NAME` -- `PROFILE_DESCRIPTION` -- `MODULE_NAME` -- `PROFILE_MODE_DEFAULT` -- `PROFILE_REQUIRED_CMDS` -- `PROFILE_SERVICES` -- `PROFILE_DEVICE_PATTERNS` -- `PROFILE_SYSFS_PATTERNS` - -Optional hooks: -- `profile_prepare` -- `profile_warmup` -- `profile_quiesce` -- `profile_post_unload` -- `profile_post_load` -- `profile_smoke` -- `profile_finalize` - -## Current starter profile + +Profiles define module-specific metadata and optional hook behavior. + +Profiles should be as declarative as possible. A profile should define what needs to be reloaded and what must be quiesced. The library should define how that is done. + +## Profile variables + +### Required or commonly used fields + +```sh +PROFILE_NAME="example_module" +PROFILE_DESCRIPTION="Example module reload validation" +MODULE_NAME="example_module" +MODULE_RELOAD_SUPPORTED="yes" +PROFILE_MODE_DEFAULT="basic" +PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed grep" +MODULE_UNLOAD_CMD="modprobe -r example_module" +MODULE_LOAD_CMD="modprobe example_module" +PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="example_module" +PROFILE_EXPECT_PRESENT_AFTER_LOAD="example_module" +PROFILE_SYSFS_PATTERNS="/sys/module/example_module" +``` + +### Service and process fields + +```sh +PROFILE_SERVICES="example.service" +PROFILE_PROC_PATTERNS="example-daemon example-client" +PROFILE_DEVICE_PATTERNS="/dev/example*" +PROFILE_SYSFS_PATTERNS="/sys/module/example_module /sys/class/example/*" +``` + +These fields are used for service status logging, evidence collection, and profile lifecycle handling. + +### Quiesce-specific fields + +Use quiesce-specific fields when the services/processes that need to be stopped before unload are different from the services/processes that should be observed or restored. + +```sh +PROFILE_QUIESCE_SERVICES="example.service" +PROFILE_QUIESCE_PROC_PATTERNS="example-daemon example-client" +PROFILE_QUIESCE_DEVICE_PATTERNS="/dev/example*" +``` + +If these are not set, the framework falls back to `PROFILE_SERVICES`, `PROFILE_PROC_PATTERNS`, and `PROFILE_DEVICE_PATTERNS`. + +### Quiesce-once behavior + +Some profiles are expensive or risky to quiesce repeatedly. For those profiles, use: + +```sh +PROFILE_QUIESCE_ONCE="yes" +``` + +This is useful for profiles such as: + +- `fastrpc`, +- `snd_soc_qcom_sdw`, +- `ath11k_ahb`, +- `msm`. + +With `PROFILE_QUIESCE_ONCE="yes"`, the first iteration performs the full quiesce path. Later iterations skip repeated service/process stop work and continue with unload/reload validation. + +### Conflict skip fields + +Use this when two profiles represent alternate transports or mutually exclusive module stacks. + +Example: + +```sh +PROFILE_SKIP_IF_MODULES_LOADED="ath11k_ahb" +``` + +This lets `ath11k_pci.profile` skip cleanly on platforms where `ath11k_ahb` is the active Wi-Fi transport. + +### Dynamic stack fields + +These fields are useful when the module to reload is a top-level holder rather than the originally named module. + +```sh +PROFILE_TOP_MODULE_CANDIDATES="snd_soc_sc8280xp snd_soc_sm8450" +PROFILE_UNLOAD_STACK="snd_soc_sc8280xp snd_soc_qcom_sdw" +PROFILE_EXTRA_UNLOAD_MODULES="" +``` + +For common patterns, prefer a library helper instead of open-coding stack discovery in the profile. + +## Profile hooks + +Profiles may define optional hooks: + +```sh +profile_prepare() { ...; } +profile_warmup() { ...; } +profile_quiesce() { ...; } +profile_post_unload() { ...; } +profile_post_load() { ...; } +profile_smoke() { ...; } +profile_finalize() { ...; } +``` + +Use hooks only when declarative profile variables are not enough. + +Recommended approach: + +1. First try generic fields such as `PROFILE_SERVICES`, `PROFILE_PROC_PATTERNS`, `MODULE_UNLOAD_CMD`, and `MODULE_LOAD_CMD`. +2. If multiple profiles need the same behavior, create a reusable helper in `lib_module_reload.sh`. +3. Keep module-specific profiles small. +4. Avoid copying large shell functions into profile files. + +## Profile lists + +Profile lists let teams or CI jobs run the desired module set without creating a separate YAML for every module. + +### `profiles/enabled.list` + +Default list used when `./run.sh` is called without `--module` or `--profile-list`. + +Keep this conservative for common CI. + +Recommended default: + +```text +fastrpc +``` + +### `profiles/base.list` + +Base-image or upstream-aligned module coverage. + +Example broad base list: + +```text +fastrpc +dwmac_qcom_eth +tc956x_pcie_eth +ath11k_pci +ath11k_ahb +ath12k_pci +qcedev_mod_dlkm +qcrypto_msm_dlkm +qrng_dlkm +spcom +mvm +venus_core +qcom_iris +snd_soc_qcom_sdw +``` + +For RB3Gen2-style targets, a conservative bring-up list can be smaller: + +```text +tc956x_pcie_eth +ath11k_ahb +venus_core +qcom_iris +snd_soc_qcom_sdw +``` + +`fastrpc` is useful but can be disruptive if the unload path hangs. It may be better to run it explicitly during bring-up. + +### `profiles/overlay.list` + +Overlay/downstream package coverage. + +Current recommended overlay list: + +```text +msm +camera +iris +audioreach +``` + +Notes: + +- `msm` represents the modern MSM DRM driver used by RB3Gen2/newer platforms. +- `msm_kgsl` is legacy KGSL and should not be the default for modern DRM-based platforms. +- `camera` and `iris` may mark themselves non-reloadable until a safe reload sequence is validated. +- `audioreach` should skip if downstream AudioReach modules are not present on the image. + +## Base module coverage ### `fastrpc.profile` -Current profile covers FastRPC unload/reload validation and supports service lifecycle-based testing. -Default mode: -- `daemon_lifecycle` +FastRPC reload validation. + +Common services/processes: + +```text +adsprpcd.service +cdsprpcd.service +adsprpcd +cdsprpcd +``` + +Guidance: + +- Stop and mask FastRPC users before unload. +- Kill remaining FastRPC cgroup/process users when required. +- Check open file descriptors for FastRPC device nodes before unload. +- Use timeout evidence if unload hangs. +- Run `fastrpc` as a focused test when debugging DSP unload behavior. +- If unload hangs and the kernel task is stuck, the device may need recovery before broad profile testing can continue. + +### `dwmac_qcom_eth.profile` + +Qualcomm DWMAC/STMMAC Ethernet reload validation. + +Typical stack: + +```text +dwmac_qcom_eth +stmmac_platform +stmmac +``` + +Use this only on platforms where `dwmac_qcom_eth` exists. + +### `tc956x_pcie_eth.profile` + +TC956x PCIe Ethernet reload validation. + +Typical module: + +```text +tc956x_pcie_eth +``` + +This is useful on RB3Gen2-style platforms where Ethernet is provided by the TC956x PCIe Ethernet driver instead of `dwmac_qcom_eth`. + +### `ath11k_pci.profile` + +ath11k PCI Wi-Fi reload validation. + +Typical stack: + +```text +ath11k_pci +ath11k +mac80211 +cfg80211 +``` + +Use `PROFILE_SKIP_IF_MODULES_LOADED="ath11k_ahb"` so this profile skips on platforms where AHB transport is active. + +### `ath11k_ahb.profile` + +ath11k AHB Wi-Fi reload validation. + +Typical stack: + +```text +ath11k_ahb +ath11k +mac80211 +cfg80211 +``` + +Common services to quiesce: + +```text +wpa_supplicant.service +NetworkManager.service +systemd-networkd.service +``` + +Use `PROFILE_QUIESCE_ONCE="yes"` if repeated service stop/start is causing long execution time or unstable network state. + +### `ath12k_pci.profile` + +ath12k PCI Wi-Fi reload validation. + +Typical stack: + +```text +ath12k_pci +ath12k +mac80211 +cfg80211 +``` + +Keep this profile even if it skips on RB3Gen2. Other targets may use ath12k. + +### `qcedev_mod_dlkm.profile` + +QCEDEV crypto DLKM reload validation. + +Typical modules: + +```text +qcedev_mod_dlkm +qce50_dlkm +``` + +### `qcrypto_msm_dlkm.profile` + +QCrypto MSM DLKM reload validation. + +Some builds may have dependency/cyclic unload issues. Capture unload logs and holder state before deciding whether the profile should stay enabled for a specific platform. + +### `qrng_dlkm.profile` + +QRNG DLKM reload validation. + +Some builds may have service naming or service lifecycle issues. Missing service units should not fail the profile by themselves. + +### `spcom.profile` + +Secure Processor communication reload validation. + +Common services to quiesce where present: + +```text +spdaemon.service +qseecomd.service +keymaster-4-0.service +``` + +Missing services are non-fatal. + +### `mvm.profile` + +MVM DLKM reload validation. + +Expected service where present: + +```text +mvm.service +``` + +### `venus_core.profile` + +Upstream Venus video reload validation. + +Typical stack: + +```text +venus_enc +venus_dec +venus_core +``` + +### `qcom_iris.profile` + +Upstream Qualcomm Iris video reload validation. + +Typical module: + +```text +qcom_iris +``` + +Use this on platforms where the active Iris module is `qcom_iris`. + +### `snd_soc_qcom_sdw.profile` + +Qualcomm ASoC/SoundWire reload validation. + +This profile should stay minimal. The topology and unload stack are handled by the library helper: + +```sh +module_reload_qcom_sdw_profile_setup +``` + +The helper detects the top-level holder of `snd_soc_qcom_sdw`, for example: + +```text +snd_soc_sc8280xp -> snd_soc_qcom_sdw +``` + +Then it unloads the top-level machine/card driver before `snd_soc_qcom_sdw`, and reloads the top-level module. + +Recommended profile behavior: + +```sh +PROFILE_NAME="snd_soc_qcom_sdw" +PROFILE_DESCRIPTION="Qualcomm ASoC/SoundWire reload validation" +PROFILE_QUIESCE_ONCE="yes" + +module_reload_qcom_sdw_profile_setup +``` + +Use `QCOM_SDW_TOP_MODULE_CANDIDATES` to extend platform support without changing the profile: + +```sh +QCOM_SDW_TOP_MODULE_CANDIDATES="snd_soc_sc8280xp snd_soc_sm8450 snd_soc_sc7280" \ + ./run.sh --module snd_soc_qcom_sdw +``` + +## Overlay module coverage + +### `msm.profile` + +Modern MSM DRM GPU/display reload validation. + +Typical module: + +```text +msm +``` + +Important distinction: + +- `msm.ko` is the modern DRM driver used by RB3Gen2/newer platforms. +- `msm_kgsl.ko` is legacy KGSL and is not expected on modern DRM-based images. + +`msm` is highly disruptive because it can be held by DRM/KMS clients, display, GPU, Weston, or console users. + +Common consumers to quiesce: + +```text +weston.service +display-manager.service +gpu-service.service +``` + +Common device paths: + +```text +/dev/dri/card* +/dev/dri/renderD* +``` + +Guidance: + +- Do not enable `msm` in broad CI until the platform-specific quiesce path is validated. +- If `modprobe -r msm` fails with `rc=1` and the unload log has no extra detail, inspect `holders.log`, `lsmod.log`, `ps.log`, `/dev/dri/*` users, and DRM clients. +- If the display stack is active, `msm` may be a valid skip/non-reloadable profile for that environment. +- Keep `msm` separate from `msm_kgsl` to avoid confusing modern DRM and legacy KGSL validation. + +### `msm_kgsl.profile` + +Legacy KGSL reload validation. + +Typical module: + +```text +msm_kgsl +``` + +This is only for old KGSL-based systems. It should skip on RB3Gen2/newer DRM systems. + +### `camera.profile` + +CAMX/downstream camera KMD reload validation. -Relevant services: -- `adsprpcd.service` -- `cdsprpcd.service` +Common module candidates: + +```text +camera +camera_kmd +camx_kmd +``` + +Upstream camera on RB3Gen2-style images may use: + +```text +qcom_camss +imx412 +camcc_sc7280 +``` + +Do not treat upstream `qcom_camss` as the same thing as CAMX overlay. If the CAMX module is not present, the CAMX overlay profile should skip. + +### `iris.profile` + +Downstream Iris video overlay reload validation. + +Common module candidates: + +```text +iris +iris_vpu +``` + +Upstream Iris uses `qcom_iris`. Keep downstream `iris` / `iris_vpu` separate from upstream `qcom_iris`. + +### `audioreach.profile` + +Downstream AudioReach reload validation. + +Typical modules: + +```text +snd_soc_qdsp6 +q6asm +q6adm +q6afe +apr +``` + +The profile should skip if downstream AudioReach modules are not present. ## Execution flow + For each selected profile: -1. Validate the profile. -2. Ensure the module is loaded before starting iteration work. -3. Run warmup hook. -4. Capture pre-state logs. -5. Run quiesce hook. -6. Attempt module unload with timeout. -7. Validate module absence. -8. Run post-unload hook. -9. Attempt module reload with timeout. -10. Validate module presence. -11. Run post-load hook. -12. Run smoke hook. -13. Capture post-load state. -14. Repeat for all iterations. -15. Run finalize hook. +1. Reset profile variables. +2. Source the profile file. +3. Run any profile setup helper. +4. Validate the profile. +5. Skip if the module is not present, built-in, marked non-reloadable, or conflicts with an active mutually exclusive module. +6. Ensure the module is loaded before iteration work starts. +7. Run warmup logic when configured. +8. Capture pre-state evidence. +9. Log service/process state for the profile. +10. Quiesce configured services/processes before unload. +11. Optionally skip repeated quiesce if `PROFILE_QUIESCE_ONCE="yes"` was already completed. +12. Execute the unload command with timeout. +13. Validate that `MODULE_NAME` and `PROFILE_EXPECT_ABSENT_AFTER_UNLOAD` are absent. +14. Run post-unload hook. +15. Execute the load command with timeout. +16. Validate that `MODULE_NAME` and `PROFILE_EXPECT_PRESENT_AFTER_LOAD` are present. +17. Run post-load hook. +18. Run smoke hook. +19. Capture post-load evidence. +20. Repeat for all iterations. +21. Run finalize hook and restore previously active services where applicable. -## Hang handling policy -Sysrq dump is **not** triggered on normal passing iterations. +## Result policy -It is triggered only when an unload/load action actually times out. +### PASS -Current behavior: -- normal pass -> no sysrq dump -- quick non-timeout failure -> normal failure evidence only -- timeout / hang -> hang evidence bundle + optional sysrq dump +A profile passes when all requested iterations complete successfully. -Default behavior in current suite: -- sysrq hang dump enabled -- but only used on timeout paths +### FAIL + +A profile fails on: + +- unload timeout, +- load timeout, +- unload command failure, +- load command failure, +- module state validation failure, +- profile hook failure, +- smoke validation failure. + +### SKIP + +A profile skips when: + +- module is not present on the image, +- module is built into the kernel, +- required command is missing, +- profile marks the module as non-reloadable, +- profile declares a conflicting active module through `PROFILE_SKIP_IF_MODULES_LOADED`. ## Evidence collected -Per profile / iteration, the suite can capture: + +Per profile and iteration, the suite can capture: + - command logs, - `lsmod`, - `modinfo`, - `ps`, - `dmesg`, -- service status and recent journal, +- service status, +- recent service journal, - profiled device path presence, - profiled sysfs path presence, - `/sys/module//holders`, @@ -130,98 +693,504 @@ Per profile / iteration, the suite can capture: Results are stored under: ```text -results/Module_Reload_Validation//iter_XX/ +Runner/suites/Kernel/Baseport/Module_Reload_Validation/results/Module_Reload_Validation//iter_XX/ +``` + +Useful files: + +```text +unload.log +load.log +pre_state/lsmod.log +pre_state/holders.log +unload_failure_state/lsmod.log +unload_failure_state/holders.log +hang_evidence/dmesg_after_sysrq.log +``` + +## Hang handling policy + +Sysrq dump is not triggered on normal passing iterations. + +It is triggered only when unload/load times out and sysrq dump policy is enabled. + +Default behavior: + +- normal pass: no sysrq dump, +- quick non-timeout failure: normal failure evidence only, +- timeout/hang: hang evidence bundle plus optional sysrq task/block dumps. + +Disable sysrq dumps when needed: + +```sh +./run.sh --module fastrpc --disable-sysrq-hang-dump ``` ## CLI usage +### Standard repo-style launch + +Most LAVA tests in this repo launch from `Runner`. + +```sh +cd Runner +$PWD/suites/Kernel/Baseport/Module_Reload_Validation/run.sh +$PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.res +$PWD/utils/result_parse.sh +``` + +### Direct local launch from the test directory + +```sh +cd Runner/suites/Kernel/Baseport/Module_Reload_Validation +./run.sh +``` + ### Run one profile + ```sh ./run.sh --module fastrpc +./run.sh --module ath11k_ahb +./run.sh --module snd_soc_qcom_sdw +./run.sh --module msm ``` -### Run one profile with more iterations +### Run a profile list + ```sh -./run.sh --module fastrpc --iterations 5 +./run.sh --profile-list profiles/base.list +./run.sh --profile-list profiles/overlay.list +``` + +### Run with more iterations + +```sh +./run.sh --module ath11k_ahb --iterations 5 ``` ### Override mode + ```sh -./run.sh --module fastrpc --mode daemon_lifecycle ./run.sh --module fastrpc --mode basic +./run.sh --module fastrpc --mode daemon_lifecycle ``` +If `--mode` is not provided, the profile default is used. + ### Override timeouts + +```sh +./run.sh --module fastrpc \ + --timeout-unload 60 \ + --timeout-load 60 \ + --timeout-settle 30 +``` + +### Enable verbose shell logging + ```sh -./run.sh --module fastrpc --timeout-unload 60 --timeout-load 60 --timeout-settle 30 +./run.sh --module snd_soc_qcom_sdw --verbose ``` -### Disable sysrq timeout-path dumps +### Disable sysrq timeout dumps + ```sh ./run.sh --module fastrpc --disable-sysrq-hang-dump ``` -### Run all enabled profiles +### Run SoundWire/audio with candidate override + ```sh -./run.sh +QCOM_SDW_TOP_MODULE_CANDIDATES="snd_soc_sc8280xp snd_soc_sm8450 snd_soc_sc7280" \ + ./run.sh --module snd_soc_qcom_sdw --iterations 1 --timeout-unload 60 --timeout-load 60 +``` + +## Team-specific launch examples + +Teams do not need separate YAML files for every profile. They can call the same module reload suite with `--module `. + +### FastRPC team example + +```sh +cd Runner +$PWD/suites/Multimedia/CDSP/fastrpc_test/run.sh || true +$PWD/utils/send-to-lava.sh $PWD/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test.res || true +$PWD/suites/Kernel/Baseport/Module_Reload_Validation/run.sh --module fastrpc || true +$PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.res || true +$PWD/utils/result_parse.sh +``` + +### Wi-Fi team examples + +```sh +cd Runner +$PWD/suites/Kernel/Baseport/Module_Reload_Validation/run.sh --module ath11k_ahb || true +$PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.res || true +$PWD/utils/result_parse.sh +``` + +```sh +cd Runner +$PWD/suites/Kernel/Baseport/Module_Reload_Validation/run.sh --module ath12k_pci || true +$PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.res || true +$PWD/utils/result_parse.sh ``` -If `--module` is empty or not given, the suite runs all profiles listed in `profiles/enabled.list`. +### Audio team example -If `--mode` is empty or not given, the profile default mode is used. +```sh +cd Runner +$PWD/suites/Kernel/Baseport/Module_Reload_Validation/run.sh --module snd_soc_qcom_sdw --iterations 1 --timeout-unload 60 --timeout-load 60 || true +$PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.res || true +$PWD/utils/result_parse.sh +``` + +### Overlay bring-up example + +```sh +cd Runner +$PWD/suites/Kernel/Baseport/Module_Reload_Validation/run.sh --profile-list suites/Kernel/Baseport/Module_Reload_Validation/profiles/overlay.list || true +$PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.res || true +$PWD/utils/result_parse.sh +``` ## YAML usage in LAVA -Current YAML is generic and takes profile input from the test plan. -Important params: -- `PROFILE` -- `ITERATIONS` -- `MODE` -- `TIMEOUT_UNLOAD` -- `TIMEOUT_LOAD` -- `TIMEOUT_SETTLE` -- `ENABLE_SYSRQ_HANG_DUMP` +`Module_Reload_Validation.yaml` should remain generic. Do not duplicate module-specific reload logic in YAML. + +Recommended params: + +```yaml +params: + PROFILE: "" + PROFILE_LIST: "" + ITERATIONS: "3" + MODE: "" + TIMEOUT_UNLOAD: "30" + TIMEOUT_LOAD: "30" + TIMEOUT_SETTLE: "20" + ENABLE_SYSRQ_HANG_DUMP: "1" +``` + +Recommended repo-aligned run steps: + +```yaml +run: + steps: + - cd Runner + - MRV_ARGS="" + - if [ -n "${PROFILE}" ]; then MRV_ARGS="${MRV_ARGS} --module ${PROFILE}"; fi + - if [ -n "${PROFILE_LIST}" ]; then MRV_ARGS="${MRV_ARGS} --profile-list ${PROFILE_LIST}"; fi + - if [ -n "${ITERATIONS}" ]; then MRV_ARGS="${MRV_ARGS} --iterations ${ITERATIONS}"; fi + - if [ -n "${MODE}" ]; then MRV_ARGS="${MRV_ARGS} --mode ${MODE}"; fi + - if [ -n "${TIMEOUT_UNLOAD}" ]; then MRV_ARGS="${MRV_ARGS} --timeout-unload ${TIMEOUT_UNLOAD}"; fi + - if [ -n "${TIMEOUT_LOAD}" ]; then MRV_ARGS="${MRV_ARGS} --timeout-load ${TIMEOUT_LOAD}"; fi + - if [ -n "${TIMEOUT_SETTLE}" ]; then MRV_ARGS="${MRV_ARGS} --timeout-settle ${TIMEOUT_SETTLE}"; fi + - if [ "${ENABLE_SYSRQ_HANG_DUMP}" = "0" ]; then MRV_ARGS="${MRV_ARGS} --disable-sysrq-hang-dump"; fi + - $PWD/suites/Kernel/Baseport/Module_Reload_Validation/run.sh ${MRV_ARGS} || true + - $PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/Module_Reload_Validation/Module_Reload_Validation.res || true + - $PWD/utils/result_parse.sh +``` Behavior: -- `PROFILE="fastrpc"` -> runs only `fastrpc.profile` -- `PROFILE=""` -> runs all enabled profiles -- `MODE=""` -> uses the profile default mode + +- `PROFILE="fastrpc"` runs only `fastrpc.profile`. +- `PROFILE="snd_soc_qcom_sdw"` runs only the audio/SoundWire profile. +- `PROFILE_LIST="suites/Kernel/Baseport/Module_Reload_Validation/profiles/base.list"` runs the base list. +- `PROFILE_LIST="suites/Kernel/Baseport/Module_Reload_Validation/profiles/overlay.list"` runs the overlay list. +- If both `PROFILE` and `PROFILE_LIST` are empty, `run.sh` uses `profiles/enabled.list`. +- If both `PROFILE` and `PROFILE_LIST` are set, prefer single-profile behavior through `PROFILE` and avoid setting both in LAVA unless the test definition intentionally supports that combination. + +### Example: generic YAML invocation for FastRPC only + +```yaml +params: + PROFILE: "fastrpc" + PROFILE_LIST: "" + ITERATIONS: "3" +``` + +### Example: generic YAML invocation for base list + +```yaml +params: + PROFILE: "" + PROFILE_LIST: "suites/Kernel/Baseport/Module_Reload_Validation/profiles/base.list" + ITERATIONS: "3" +``` + +### Example: generic YAML invocation for overlay list + +```yaml +params: + PROFILE: "" + PROFILE_LIST: "suites/Kernel/Baseport/Module_Reload_Validation/profiles/overlay.list" + ITERATIONS: "3" +``` + +### Do we need one YAML per profile? + +No. The preferred approach is one generic YAML plus params. + +Use separate YAML files only when a team wants to combine module reload validation with another functional test flow, for example FastRPC functional validation followed by `--module fastrpc` reload validation. ## How to add a new profile -1. Create a new file under `profiles/`, for example: - - `profiles/ath11k_pci.profile` -2. Define the required metadata: - - `PROFILE_NAME` - - `MODULE_NAME` -3. Add hooks only if module-specific lifecycle handling is needed. -4. Add the profile basename to `profiles/enabled.list`. -5. Run locally with: + +1. Create a profile file: + + ```text + profiles/example_module.profile + ``` + +2. Start with minimal metadata: + + ```sh + PROFILE_NAME="example_module" + PROFILE_DESCRIPTION="Example module reload validation" + MODULE_NAME="example_module" + MODULE_RELOAD_SUPPORTED="yes" + PROFILE_MODE_DEFAULT="basic" + PROFILE_REQUIRED_CMDS="modprobe rmmod ps sed grep" + MODULE_UNLOAD_CMD="modprobe -r example_module" + MODULE_LOAD_CMD="modprobe example_module" + PROFILE_EXPECT_ABSENT_AFTER_UNLOAD="example_module" + PROFILE_EXPECT_PRESENT_AFTER_LOAD="example_module" + PROFILE_SYSFS_PATTERNS="/sys/module/example_module" + ``` + +3. Add quiesce data only if the module has active users: + + ```sh + PROFILE_QUIESCE_SERVICES="example.service" + PROFILE_QUIESCE_PROC_PATTERNS="example-daemon example-client" + PROFILE_DEVICE_PATTERNS="/dev/example*" + ``` + +4. Use `PROFILE_QUIESCE_ONCE="yes"` if repeated service quiesce should happen only once per profile run. + +5. Add conflict rules if this profile is mutually exclusive with another profile: + + ```sh + PROFILE_SKIP_IF_MODULES_LOADED="other_transport_module" + ``` + +6. If the module has holders, unload the top-level holder first: + + ```sh + PROFILE_TOP_MODULE_CANDIDATES="example_card example_machine" + module_reload_profile_setup_stack + ``` + + Or create a purpose-built helper in `lib_module_reload.sh` if the logic is reusable. + +7. Add optional hooks only when required. + +8. Add the profile basename to the appropriate list: + + - `enabled.list` for default CI, + - `base.list` for base-image modules, + - `overlay.list` for overlay/downstream modules, + - team-specific lists if needed. + +9. Run locally: + + ```sh + ./run.sh --module example_module --iterations 1 + ``` + +10. Run shellcheck: + + ```sh + shellcheck -s sh Runner/suites/Kernel/Baseport/Module_Reload_Validation/run.sh + shellcheck -s sh Runner/utils/lib_module_reload.sh + shellcheck -s sh Runner/suites/Kernel/Baseport/Module_Reload_Validation/profiles/example_module.profile + ``` + +## Customizing profile lists + +### Create a team-specific list + +Example: + +```text +profiles/wifi.list +``` + +```text +ath11k_pci +ath11k_ahb +ath12k_pci +``` + +Run it: ```sh -./run.sh --module ath11k_pci +./run.sh --profile-list profiles/wifi.list ``` -No YAML duplication is needed for new profiles. +### Create a platform-specific list -## Result policy +Example: -### PASS -- all requested iterations for a profile pass successfully. +```text +profiles/rb3gen2.list +``` -### FAIL -- unload/load timeout, -- unload/load command failure, -- module state validation failure, -- profile hook failure, -- smoke validation failure. +```text +tc956x_pcie_eth +ath11k_ahb +venus_core +qcom_iris +snd_soc_qcom_sdw +``` + +Run it: + +```sh +./run.sh --profile-list profiles/rb3gen2.list +``` + +### Keep disruptive profiles out of default CI + +Do not put every profile into `enabled.list`. + +Profiles that can disrupt board access or display state should be run explicitly or through prepared profile lists: + +- `fastrpc`, +- `ath11k_ahb`, +- `ath11k_pci`, +- `snd_soc_qcom_sdw`, +- `msm`, +- `camera`, +- `iris`, +- `audioreach`. + +## Troubleshooting + +### Profile skips with “module not present on image” + +Check: + +```sh +lsmod | grep +modinfo +find /lib/modules/$(uname -r) /usr/lib/modules/$(uname -r) -name '.ko*' +``` + +This is expected when a profile is valid for another target but not present on the current image. + +### Profile skips with “conflicting active module is loaded” + +This means the profile is for an alternate transport/stack. + +Example: + +```text +ath11k_pci SKIP - conflicting active module is loaded: ath11k_ahb +``` + +Run the active transport profile instead: + +```sh +./run.sh --module ath11k_ahb +``` + +### `modprobe -r ` fails with `rc=1` + +Inspect: + +```sh +cat results/Module_Reload_Validation//iter_01/unload.log +cat results/Module_Reload_Validation//iter_01/unload_failure_state/holders.log +cat results/Module_Reload_Validation//iter_01/unload_failure_state/lsmod.log +cat results/Module_Reload_Validation//iter_01/unload_failure_state/ps.log +``` + +Common causes: + +- another module is holding the target, +- a userspace process has an open device node, +- a service restarted after quiesce, +- the module is part of the active display/audio/network path, +- the profile is targeting the wrong module variant for the platform. + +### `fastrpc` unload times out + +Check: + +```sh +cat results/Module_Reload_Validation/fastrpc/iter_01/hang_evidence/timeout_summary.log +cat results/Module_Reload_Validation/fastrpc/iter_01/hang_evidence/holders.log +cat results/Module_Reload_Validation/fastrpc/iter_01/hang_evidence/ps.log +cat results/Module_Reload_Validation/fastrpc/iter_01/hang_evidence/dmesg_after_sysrq.log +``` + +If the unload task is stuck in kernel space, the framework can capture evidence but cannot always recover the kernel unload path in-place. + +### `snd_soc_qcom_sdw` takes too long + +Use: + +```sh +PROFILE_QUIESCE_ONCE="yes" +``` + +Also run with fewer iterations during bring-up: + +```sh +./run.sh --module snd_soc_qcom_sdw --iterations 1 --timeout-unload 60 --timeout-load 60 +``` + +### `msm` unload fails + +`msm.ko` is the modern DRM display/GPU driver and may be held by active display/GPU clients. + +Inspect: + +```sh +lsmod | grep '^msm ' +ls -l /dev/dri/ +cat results/Module_Reload_Validation/msm/iter_01/unload_failure_state/holders.log +cat results/Module_Reload_Validation/msm/iter_01/unload_failure_state/ps.log +``` + +If active display is required for the test environment, keep `msm` out of broad overlay lists or mark it non-reloadable for that platform until a safe quiesce path is validated. + +## Safety notes + +This suite is intended for profiled, supported modules only. It should not blindly reload every loaded kernel module. + +Some profiles are disruptive: + +- Wi-Fi reload can interrupt network access. +- Ethernet reload can interrupt remote access. +- Display/GPU reload can stop Weston or display-manager. +- Camera reload can stop camera pipelines. +- Audio reload can stop active audio services. +- FastRPC reload can impact DSP clients. + +Keep `enabled.list` conservative for common CI. Run disruptive profiles explicitly or through prepared profile lists when the test plan expects those side effects. + +## Platform notes + +Module names differ across Qualcomm platforms and image combinations. + +Examples: + +- Wi-Fi can appear as `ath11k_pci`, `ath11k_ahb`, or `ath12k_pci`. +- Ethernet can appear as `dwmac_qcom_eth` or `tc956x_pcie_eth`. +- Upstream video can appear as `venus_core` or `qcom_iris`. +- Downstream video overlay can appear as `iris` or `iris_vpu`. +- Modern GPU/display uses `msm.ko`. +- Legacy KGSL uses `msm_kgsl.ko` and is not expected on modern RB3Gen2/newer DRM stacks. +- SoundWire/ASoC reload should target the top-level holder of `snd_soc_qcom_sdw`, not always `snd_soc_qcom_sdw` directly. + +Use these commands before deciding which profile belongs in a platform list: + +```sh +lsmod +ls /sys/module//holders 2>/dev/null +modinfo +find /lib/modules/$(uname -r) /usr/lib/modules/$(uname -r) -name '*.ko*' | grep -E '|' +``` -### SKIP -- module not present, -- module built into the kernel, -- required commands not available, -- profile explicitly not reloadable. - -## Notes -- This suite is intended for **profiled, supported modules**, not blind reload of every loaded kernel module. -- The current structure avoids hidden run.sh-to-library globals as much as possible by passing explicit arguments and hook context. -- Profile hooks receive context arguments from the engine, so module-specific logic can store logs in the correct iteration directory without depending on hidden globals.