#!/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 "$@"