Files

116 lines
3.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Reset Intel SOF audio PCI driver (sof-audio-pci-intel-cnl) for 0000:00:1f.3
# Goal: recover from SOF/HDA DMA channel exhaustion ("hda-dmac: ... no free channel")
# that manifests as HDMI hw_params failures / ipc tx error -5 in kernel logs.
#
# IMPORTANT:
# - This script is intended to be run as root (sudo).
# - For unattended automation from tools without a TTY, add a single sudoers NOPASSWD entry, e.g.:
# jack ALL=(root) NOPASSWD: /home/jack/文档/chromebox_10th_audio_driver/scripts/reset-sof-hdmi-pci.sh
#
# Usage:
# sudo bash scripts/reset-sof-hdmi-pci.sh
# sudo bash scripts/reset-sof-hdmi-pci.sh --verify-pcm2
#
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DOCTOR="${REPO_ROOT}/scripts/kaisa-audio-doctor.sh"
DEV_PCI="${DEV_PCI:-0000:00:1f.3}"
DRIVER_NAME="${DRIVER_NAME:-sof-audio-pci-intel-cnl}"
DRIVER_SYSFS="/sys/bus/pci/drivers/${DRIVER_NAME}"
DESKTOP_USER="${DESKTOP_USER:-jack}"
VERIFY_PCM2=0
if [[ "${1:-}" == "--verify-pcm2" ]]; then
VERIFY_PCM2=1
fi
log() { printf '[%s] %s\n' "$(date '+%F %T')" "$*"; }
require_root() {
if [[ "${EUID}" -ne 0 ]]; then
echo "ERROR: run as root: sudo bash $0" >&2
exit 1
fi
}
mount_debugfs_if_needed() {
if mountpoint -q /sys/kernel/debug; then
log "debugfs already mounted"
return 0
fi
log "mounting debugfs on /sys/kernel/debug"
mount -t debugfs none /sys/kernel/debug
}
stop_user_audio() {
log "stopping user audio services for ${DESKTOP_USER}"
# Use sudo -u to target the desktop user's systemd --user session.
# This requires root privileges (this script runs as root).
sudo -u "${DESKTOP_USER}" XDG_RUNTIME_DIR="/run/user/$(id -u "${DESKTOP_USER}")" \
systemctl --user stop wireplumber pipewire-pulse pipewire || true
sleep 1
}
start_user_audio() {
log "starting user audio services for ${DESKTOP_USER}"
sudo -u "${DESKTOP_USER}" XDG_RUNTIME_DIR="/run/user/$(id -u "${DESKTOP_USER}")" \
systemctl --user start pipewire pipewire-pulse wireplumber || true
sleep 2
}
pci_reset() {
if [[ ! -d "${DRIVER_SYSFS}" ]]; then
echo "ERROR: driver sysfs dir missing: ${DRIVER_SYSFS}" >&2
ls -la /sys/bus/pci/drivers | grep -i sof || true
exit 1
fi
log "unbinding ${DEV_PCI} from ${DRIVER_NAME}"
echo "${DEV_PCI}" >"${DRIVER_SYSFS}/unbind"
sleep 1
log "binding ${DEV_PCI} to ${DRIVER_NAME}"
echo "${DEV_PCI}" >"${DRIVER_SYSFS}/bind"
sleep 2
}
tail_kernel_hints() {
log "kernel hints (last ~120 matching lines)"
journalctl -k -b --no-pager 2>/dev/null | \
grep -nE 'sof-audio-pci-intel-cnl|Firmware file:|Topology file:|Firmware info: version|ipc tx error|sof_ipc3_pcm_hw_params|hda-dmac|dma_channel_get|ASoC error|HDMI[0-9]|pcm[0-9]+' | \
tail -n 120 || true
}
maybe_verify() {
if [[ "${VERIFY_PCM2}" -ne 1 ]]; then
return 0
fi
if [[ ! -x "${DOCTOR}" ]]; then
echo "WARN: doctor script missing: ${DOCTOR}" >&2
return 0
fi
log "running doctor verify (pcm2) as ${DESKTOP_USER}"
sudo -u "${DESKTOP_USER}" XDG_RUNTIME_DIR="/run/user/$(id -u "${DESKTOP_USER}")" \
bash -lc "cd '${REPO_ROOT}' && ./scripts/kaisa-audio-doctor.sh --verify --only-pcm 2" || true
}
main() {
require_root
mount_debugfs_if_needed
stop_user_audio
pci_reset
start_user_audio
tail_kernel_hints
maybe_verify
log "done"
}
main "$@"