Skip to content

Instantly share code, notes, and snippets.

@loopyd
Last active March 12, 2024 07:03
Show Gist options
  • Save loopyd/663cf1c8cc8f5f27e9c6268983fea9df to your computer and use it in GitHub Desktop.
Save loopyd/663cf1c8cc8f5f27e9c6268983fea9df to your computer and use it in GitHub Desktop.
[bash] HP Omen Fix for Linux Mint - Fixes error with missing audio firmware on this laptop
#!/bin/bash
# This script is used to fix the audio issues on HP Omen 15 laptop
#
# It installs the latest kernel, updates the sof firmware, removes old kernels, enables real-time audio support and disables mitigations for better performance, as well
# as applies additional tweaks to improve the overall system performance and stability on this laptop.
# Function to update sof firmware from sof project to the specified version
function update_sof() {
local sof_firmware_version="${1}"
local backup_folder="${2}"
WORKDIR=$(mktemp -d)
mkdir -p ${WORKDIR}/sof-bin
cd ${WORKDIR}/sof-bin || {
echo "Could not change to ${WORKDIR}/sof-bin directory." >&2
return 1
}
wget -O - "https://github.com/thesofproject/sof-bin/releases/download/v${sof_firmware_version}/sof-bin-${sof_firmware_version}.tar.gz" | tar xz
if [ $? -ne 0 ]; then
echo "Could not download sof-bin package from sof project." >&2
return 1
fi
cd "sof-bin-${sof_firmware_version}" || {
echo "Could not find sof-bin-${sof_firmware_version} directory." >&2
return 1
}
# Take backup, just in case of issues.
if [ ! -d "${backup_folder}" ]; then
echo "Saving backup to: ${backup_folder} ..." >&2
mkdir -p "${backup_folder}" 2>/dev/null
sudo mv /lib/firmware/intel/sof* "${backup_folder}" 2>/dev/null
sudo mv /usr/local/bin/sof-* "${backup_folder}" 2>/dev/null
fi
# Run the installer from the downloaded package
echo "Installing sf-bin firmware package from: ${WORKDIR}/sof-bin/sof-bin-${sof_firmware_version} ..." >&2
sudo chmod +x ./install.sh
sudo ./install.sh >&2
if [ $? -ne 0 ]; then
echo "Failed to install sof-bin package, please check terminal output for details" >&2
return 1
fi
# Cleanup the build directory
cd "$HOME" || {
echo "Could not change to home directory." >&2
return 1
}
echo "Cleaning build directory ..." >&2
rm -rf "${WORKDIR}"/sof-bin 2>/dev/null
}
# Function to install a new kernel
function install_kernel() {
local NEW_KERNEL="${1}"
local EXECUTE="${2}"
IN_USE=$(uname -a | awk '{ print $3 }')
if [[ "$IN_USE" == "$NEW_KERNEL" ]]; then
echo "[WARN] The requested kernel: $NEW_KERNEL is already in use!" >&2
fi
NEW_KERNEL_PACKAGES=$(
apt-cache search "${NEW_KERNEL}" |
grep -Evi "unsigned|nvidia|uc|-dbgsym" |
grep -Ei 'linux-image|linux-headers|linux-modules|linux-modules-extra' |
awk '{ print $1 }'
)
if [[ "$EXECUTE" == "true" ]]; then
for PACKAGE in $NEW_KERNEL_PACKAGES; do
if dpkg -l | grep -q "$PACKAGE"; then
echo "[WARN] Kernel package: $PACKAGE is already installed." >&2
continue
fi
echo "[APT] Installing kernel package: $PACKAGE" >&2
sudo apt install -qqy --no-install-recommends "$PACKAGE" || {
echo "[ERROR] Failed to install kernel package: $PACKAGE" >&2
return 1
}
done
echo "[SUCCESS] Please reboot your system to complete the kernel installation." >&2
return 0
else
echo "[SUCCESS] To install the new kernel, run this function with the second argument set to 'true'." >&2
return 0
fi
}
# Function to remove old kernels
#shellcheck disable=SC2120
function remove_old_kernels() {
local EXECUTE="${1}"
local USE_KERNEL="${2}"
IN_USE=$(uname -a | awk '{ print $3 }')
if [[ "$IN_USE" == "$USE_KERNEL" ]]; then
echo "[WARN] The requested kernel: $USE_KERNEL is in use!" >&2
fi
OLD_KERNELS=$(
dpkg --list |
grep -v "$IN_USE" |
grep -v "$USE_KERNEL" |
grep -Ei 'linux-image|linux-headers|linux-modules|linux-modules-extra' |
awk '{ print $2 }'
)
if [[ "$EXECUTE" == "true" ]]; then
for PACKAGE in $OLD_KERNELS; do
echo "[APT] Removing kernel package: $PACKAGE" >&2
yes | sudo apt purge -qq "$PACKAGE" || {
echo "[ERRPR] Failed to remove kernel package: $PACKAGE" >&2
return 1
}
done
echo "[ALERT] Please reboot your system to complete the kernel removal." >&2
return 0
else
echo "[SUCCESS] To remove old kernels, run this function with the first argument set to 'true'." >&2
return 0
fi
}
# Function to enable real-time audio support for PREEMPT_DYNAMIC kernel
function enable_rt_preempt_audio() {
# check if the kernel is PREEMPT_DYNAMIC
if ! grep -q PREEMPT_DYNAMIC /boot/config-"$(uname -r)"; then
echo "[ERROR] Real-time audio support is only available for PREEMPT_DYNAMIC kernel." >&2
return 1
fi
# if audio group does not exist, create it
if ! grep -q audio /etc/group; then
echo "[INFO] Creating audio group ..." >&2
sudo groupadd audio || {
echo "[ERROR] Failed to create audio group." >&2
return 1
}
echo "[SUCCESS] Audio group is now created." >&2
else
echo "[WARN] Audio group is already created." >&2
fi
# add current user to audio group, if not already added
if ! groups | grep -q audio; then
echo "[INFO] Adding current user to audio group ..." >&2
sudo usermod -aG audio "$USER" || {
echo "[ERROR] Failed to add current user to audio group." >&2
return 1
}
echo "[SUCCESS] Current user is now added to audio group." >&2
else
echo "[WARN] Current user is already added to audio group." >&2
fi
# if ondemand service is running, stop it
if sudo systemctl is-active --quiet ondemand; then
echo "[INFO] Stopping ondemand service ..." >&2
sudo systemctl stop ondemand.service || {
echo "[ERROR] Failed to stop ondemand service." >&2
return 1
}
echo "[SUCCESS] ondemand service is now stopped." >&2
else
echo "[WARN] ondemand service is already stopped." >&2
fi
# if ondemand service is unmasked, mask it
if ! sudo systemctl is-enabled --quiet ondemand; then
echo "[INFO] Masking ondemand service ..." >&2
sudo systemctl mask ondemand || {
echo "[ERROR] Failed to mask ondemand service." >&2
return 1
}
echo "[SUCCESS] ondemand service is now masked." >&2
else
echo "[WARN] ondemand service is already masked." >&2
fi
# install real-time audio service
if [ ! -f /etc/systemd/system/rt-audio-setup.service ]; then
echo "[INFO] Enabling real-time audio service ..." >&2
sudo tee /etc/systemd/system/rt-audio-setup.service <<EOF
[Unit]
Description=Realtime Audio Setup
[Service]
Type=oneshot
ExecStart=/bin/bash /usr/local/bin/rt-audio-setup
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
sudo cat /usr/local/bin/rt-audio-setup <<EOF
echo -n performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
echo -n 950000 | sudo tee /proc/sys/kernel/sched_rt_runtime_us
EOF
sudo chmod +x /usr/local/bin/rt-audio-setup
sudo systemctl enable rt-audio-setup || {
echo "[ERROR] Failed to enable real-time audio service." >&2
return 1
}
sudo systemctl start rt-audio-setup || {
echo "[ERROR] Failed to start real-time audio service." >&2
return 1
}
echo "[SUCCESS] Real-time audio service is now enabled." >&2
else
echo "[WARN] Real-time audio service is already enabled." >&2
fi
# Set real-time audio limits for audio group
if [ -f /etc/security/limits.d/audio.conf ]; then
echo "[WARN] Real-time audio limits are already set." >&2
else
echo "[INFO] Setting real-time audio limits ..." >&2
sudo cat /etc/security/limits.d/audio.conf <<EOF
@audio - rtprio 99
@audio - memlock unlimited
EOF
echo "[SUCCESS] Real-time audio limits are now set." >&2
fi
# Uncomment vm.swappiness line in sysctl.conf
if grep -q "#vm.swappiness" /etc/sysctl.conf; then
sudo sed -i 's/#vm.swappiness/vm.swappiness/' /etc/sysctl.conf || {
echo "[ERROR] Failed to uncomment vm.swappiness line." >&2
return 1
}
fi
# Add vm.swappiness line to sysctl.conf if not found
if ! grep -q "vm.swappiness" /etc/sysctl.conf; then
echo "[INFO] Adding vm.swappiness line to sysctl.conf ..." >&2
sudo tee -a /etc/sysctl.conf <<EOF
vm.swappiness=10
EOF
echo "[SUCCESS] vm.swappiness line is now added to sysctl.conf." >&2
fi
# Adjust swappiness to 10.
SWAPPINESS=$(grep -Ei 'vm.swappiness' /etc/sysctl.conf | awk '{ print $3 }')
if [[ "$SWAPPINESS" != "10" ]]; then
echo "[INFO] Setting vm.swappiness to 10 ..." >&2
sudo sed -i 's/vm.swappiness=.*$/vm.swappiness=10/' /etc/sysctl.conf || {
echo "[ERROR] Failed to set vm.swappiness to 10." >&2
return 1
}
echo "[SUCCESS] vm.swappiness is now set to 10." >&2
else
echo "[WARN] vm.swappiness is already set to 10." >&2
fi
# Add udev rule for cpu_dma_latency
if [ -f /etc/udev/rules.d/50-cpu_dma_latency.rules ]; then
echo "[WARN] udev rule for cpu_dma_latency is already added." >&2
else
echo "[INFO] Adding udev rule for cpu_dma_latency ..." >&2
sudo cat /etc/udev/rules.d/50-cpu_dma_latency.rules <<EOF
DEVPATH=="/devices/virtual/misc/cpu_dma_latency", OWNER="root", GROUP="audio", MODE="0660"
EOF
sudo udevadm control --reload-rules || {
echo "[ERROR] Failed to reload udev rules." >&2
return 1
}
sudo udevadm trigger || {
echo "[ERROR] Failed to trigger udev rules." >&2
return 1
}
echo "[SUCCESS] udev rule for cpu_dma_latency is now added." >&2
fi
return 0
}
# Function to enable or disable kernel arguments
function enable_kernelarg() {
local KERNELARGS=()
KERNELARGS=("${@}")
# If the GRUB_CMDLINE_LINUX_DEFAULT line is not found, add it
if ! grep -q GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub; then
echo "[INFO] Adding GRUB_CMDLINE_LINUX_DEFAULT line ..." >&2
sudo sed -i 's/GRUB_CMDLINE_LINUX=\"/GRUB_CMDLINE_LINUX_DEFAULT=\"/g' /etc/default/grub || {
echo "[ERROR] Failed to add GRUB_CMDLINE_LINUX_DEFAULT line." >&2
return 1
}
fi
# If the GRUB_CMDLINE_LINUX_DEFAULT line is commented out, uncomment it
if grep -q "#GRUB_CMDLINE_LINUX_DEFAULT" /etc/default/grub; then
sudo sed -i 's/#GRUB_CMDLINE_LINUX_DEFAULT/GRUB_CMDLINE_LINUX_DEFAULT/g' /etc/default/grub || {
echo "[ERROR] Failed to uncomment GRUB_CMDLINE_LINUX_DEFAULT line." >&2
return 1
}
fi
for KERNELARG in "${KERNELARGS[@]}"; do
if grep -q "${KERNELARG}" /etc/default/grub; then
echo "[WARN] Kernel argument: ${KERNELARG} is already enabled." >&2
continue
fi
# Add the kernel argument to the GRUB_CMDLINE_LINUX_DEFAULT line
echo "[INFO] Enabling kernel argument: ${KERNELARG} ..." >&2
sudo sed -i "s/GRUB_CMDLINE_LINUX_DEFAULT=\"/GRUB_CMDLINE_LINUX_DEFAULT=\"${KERNELARG} /" /etc/default/grub || {
echo "[ERROR] Failed to enable kernel argument: ${KERNELARG}" >&2
return 1
}
sudo update-grub >&2 || {
echo "[ERROR] Failed to update grub." >&2
return 1
}
echo "[SUCCESS] Kernel argument: ${KERNELARG} is now enabled." >&2
done
return 0
}
function disable_kernelarg() {
local KERNELARGS=()
KERNELARGS=("${@}")
# if the GRUB_CMDLINE_LINUX_DEFAULT line is not found, return
if ! grep -q GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub; then
echo "[WARN] GRUB_CMDLINE_LINUX_DEFAULT line is not found, doing nothing." >&2
return 0
fi
# if the GRUB_CMDLINE_LINUX_DEFAULT line is commented out, return
if grep -q "#GRUB_CMDLINE_LINUX_DEFAULT" /etc/default/grub; then
echo "[WARN] GRUB_CMDLINE_LINUX_DEFAULT line is commented out, doing nothing." >&2
return 0
fi
# remove the kernel arguments from the GRUB_CMDLINE_LINUX_DEFAULT line
for KERNELARG in "${KERNELARGS[@]}"; do
if ! grep -q "${KERNELARG}" /etc/default/grub; then
echo "[WARN] Kernel argument: ${KERNELARG} is already disabled." >&2
return 0
fi
echo "[INFO] Disabling kernel argument: ${KERNELARG} ..." >&2
sudo sed -i "s/${KERNELARG} //" /etc/default/grub || {
echo "[ERROR] Failed to disable kernel argument: ${KERNELARG}" >&2
return 1
}
sudo update-grub >&2 || {
echo "[ERROR] Failed to update grub." >&2
return 1
}
done
return 0
}
install_kernel "6.5.0-1014-oem" "true"
update_sof "2023.12" "$HOME/sof-fw-backup"
remove_old_kernels "true" "6.5.0-1014-oem"
disable_kernelarg nospalsh
enable_kernelarg quiet splash threadirqs mitigations=off
enable_rt_preempt_audio
@loopyd
Copy link
Author

loopyd commented Feb 8, 2024

Update: Lock kernel version to 6.5.0-1014-oem and add kernel autocleanup script.

@loopyd
Copy link
Author

loopyd commented Mar 12, 2024

Update: Real-time dynamic preempt auto-configuration and tweaks have been added with PREEMPT_DYNAMIC support. See: linuxaudio for details. These added tweaks fully pass a rtcqs sanity check for real-time audio and improve the overall performance of the laptop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment