Last active
November 7, 2024 21:54
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
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.
how do i run or add this?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Update: Lock kernel version to 6.5.0-1014-oem and add kernel autocleanup script.