mirror of
https://github.com/aviallon/nixos-lib.git
synced 2026-04-05 17:27:50 +00:00
[Laptop] Add option to force PCIe ASPM
This commit is contained in:
parent
fb0b741ea1
commit
5cda91672c
3 changed files with 325 additions and 0 deletions
38
packages/aspm_enable/default.nix
Normal file
38
packages/aspm_enable/default.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{lib
|
||||
,bc
|
||||
,pciutils
|
||||
,gnugrep
|
||||
,coreutils
|
||||
,bash
|
||||
,writeText
|
||||
,stdenv
|
||||
,substituteAll
|
||||
}:
|
||||
with lib;
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "aspm_enable";
|
||||
version = "2022-04-09";
|
||||
|
||||
src = ./src;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin;
|
||||
cp -v aspm_enable.sh $out/bin/aspm_enable
|
||||
substituteInPlace $out/bin/aspm_enable \
|
||||
--replace bc ${bc}/bin/bc \
|
||||
--replace lspci ${pciutils}/bin/lspci \
|
||||
--replace setpci ${pciutils}/bin/setpci \
|
||||
--replace grep ${gnugrep}/bin/grep;
|
||||
substituteAllInPlace $out/bin/aspm_enable;
|
||||
'';
|
||||
|
||||
buildInputs = [ pciutils bc coreutils gnugrep ];
|
||||
|
||||
meta = {
|
||||
description = "A program to forcibly enable PCIe ASPM for compatible devices";
|
||||
homepage = "https://wireless.wiki.kernel.org/en/users/Documentation/ASPM";
|
||||
license = licenses.gpl3Plus;
|
||||
patforms = [ "x86_64-linux" "i686-linux" "aarch64-linux" "mipsel-linux" ];
|
||||
maintainers = with maintainers; [ ];
|
||||
};
|
||||
}
|
||||
267
packages/aspm_enable/src/aspm_enable.sh
Executable file
267
packages/aspm_enable/src/aspm_enable.sh
Executable file
|
|
@ -0,0 +1,267 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2010-2013 Luis R. Rodriguez <mcgrof@do-not-panic.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# ASPM Tuning script
|
||||
#
|
||||
# This script lets you enable ASPM on your devices in case your BIOS
|
||||
# does not have it enabled for some reason. If your BIOS does not have
|
||||
# it enabled it is usually for a good reason so you should only use this if
|
||||
# you know what you are doing. Typically you would only need to enable
|
||||
# ASPM manually when doing development and using a card that typically
|
||||
# is not present on a laptop, or using the cardbus slot. The BIOS typically
|
||||
# disables ASPM for foreign cards and on the cardbus slot. Check also
|
||||
# if you may need to do other things than what is below on your vendor
|
||||
# documentation.
|
||||
#
|
||||
# To use this script You will need for now to at least query your device
|
||||
# PCI endpoint and root complex addresses using the convention output by
|
||||
# lspci: [<bus>]:[<slot>].[<func>]
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# 03:00.0 Network controller: Atheros Communications Inc. AR9300 Wireless LAN adaptor (rev 01
|
||||
# 00:1c.1 PCI bridge: Intel Corporation 82801H (ICH8 Family) PCI Express Port 2 (rev 03)
|
||||
#
|
||||
# The root complex for the endpoint can be found using lspci -t
|
||||
#
|
||||
# For more details refer to:
|
||||
#
|
||||
# http://wireless.kernel.org/en/users/Documentation/ASPM
|
||||
|
||||
# We'll only enable the last 2 bits by using a mask
|
||||
# of :3 to setpci, this will ensure we keep the existing
|
||||
# values on the byte.
|
||||
#
|
||||
# Hex Binary Meaning
|
||||
# -------------------------
|
||||
# 0 0b00 L0 only
|
||||
# 1 0b01 L0s only
|
||||
# 2 0b10 L1 only
|
||||
# 3 0b11 L1 and L0s
|
||||
|
||||
function aspm_setting_to_string()
|
||||
{
|
||||
case $1 in
|
||||
0)
|
||||
echo -e "\t${BLUE}L0 only${NORMAL}, ${RED}ASPM disabled${NORMAL}"
|
||||
;;
|
||||
1)
|
||||
;;
|
||||
2)
|
||||
echo -e "\t${GREEN}L1 only${NORMAL}"
|
||||
;;
|
||||
3)
|
||||
echo -e "\t${GREEN}L1 and L0s${NORMAL}"
|
||||
;;
|
||||
*)
|
||||
echo -e "\t${RED}Invalid${NORMAL}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
###################################################################
|
||||
# Do not edit below here unless you are sending me a patch
|
||||
###################################################################
|
||||
#
|
||||
# TODO: patches are welcomed to me until we submit to to
|
||||
# PCI Utilities upstream.
|
||||
#
|
||||
# This can be improved by in this order:
|
||||
#
|
||||
# * Accept arguments for endpoint and root complex address, and
|
||||
# desired ASPM settings
|
||||
# * Look for your ASPM capabilities by quering your
|
||||
# LnkCap register first. Use these values to let you
|
||||
# select whether you want to enable only L1 or L1 & L0s
|
||||
# * Searching for your root complex for you
|
||||
# * Search for your PCI device by using the driver
|
||||
# * Disable your driver and ask to reboot ?
|
||||
# * Rewrite in C
|
||||
# * Write ncurses interface [ wishlist ]
|
||||
# * Write GTK/QT interface [ wishlist ]
|
||||
# * Submit upstream as aspm.c to the PCI Utilities, which are
|
||||
# maintained by Martin Mares <mj@ucw.cz>
|
||||
|
||||
# Pretty colors
|
||||
GREEN="\033[01;32m"
|
||||
YELLOW="\033[01;33m"
|
||||
NORMAL="\033[00m"
|
||||
BLUE="\033[34m"
|
||||
RED="\033[31m"
|
||||
PURPLE="\033[35m"
|
||||
CYAN="\033[36m"
|
||||
UNDERLINE="\033[02m"
|
||||
|
||||
# we can surely read the spec to get a better value
|
||||
MAX_SEARCH=50
|
||||
|
||||
function enable_aspm() {
|
||||
|
||||
ENDPOINT="$1"
|
||||
shift 1
|
||||
ASPM_SETTING="${1:-3}"
|
||||
shift 1
|
||||
|
||||
SEARCH_COUNT=1
|
||||
ASPM_BYTE_ADDRESS="INVALID"
|
||||
|
||||
ENDPOINT_PRESENT=$(lspci | grep -c "$ENDPOINT")
|
||||
|
||||
if [[ $(id -u) != 0 ]]; then
|
||||
echo "This needs to be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $ENDPOINT_PRESENT -eq 0 ]]; then
|
||||
echo "Endpoint $ENDPOINT is not present"
|
||||
exit
|
||||
fi
|
||||
|
||||
# XXX: lspci -s some_device_not_existing does not return positive
|
||||
# if the device does not exist, fix this upstream
|
||||
function device_present()
|
||||
{
|
||||
|
||||
PRESENT=$(lspci | grep -c "$1")
|
||||
COMPLAINT="${RED}not present${NORMAL}"
|
||||
|
||||
if [[ $PRESENT -eq 0 ]]; then
|
||||
if [[ $2 != "present" ]]; then
|
||||
COMPLAINT="${RED}disappeared${NORMAL}"
|
||||
fi
|
||||
|
||||
echo -e "Device ${BLUE}${1}${NORMAL} $COMPLAINT"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function find_aspm_byte_address()
|
||||
{
|
||||
device_present $ENDPOINT present
|
||||
if [[ $? -ne 0 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
SEARCH=$(setpci -s $1 34.b)
|
||||
# We know on the first search $SEARCH will not be
|
||||
# 10 but this simplifies the implementation.
|
||||
while [[ $SEARCH != 10 && $SEARCH_COUNT -le $MAX_SEARCH ]]; do
|
||||
END_SEARCH=$(setpci -s $1 ${SEARCH}.b)
|
||||
|
||||
# Convert hex digits to uppercase for bc
|
||||
SEARCH_UPPER=$(printf "%X" 0x${SEARCH})
|
||||
|
||||
if [[ $END_SEARCH = 10 ]]; then
|
||||
ASPM_BYTE_ADDRESS=$(echo "obase=16; ibase=16; $SEARCH_UPPER + 10" | bc)
|
||||
break
|
||||
fi
|
||||
|
||||
SEARCH=$(echo "obase=16; ibase=16; $SEARCH + 1" | bc)
|
||||
SEARCH=$(setpci -s $1 ${SEARCH}.b)
|
||||
|
||||
((SEARCH_COUNT++))
|
||||
done
|
||||
|
||||
if [[ $SEARCH_COUNT -ge $MAX_SEARCH ]]; then
|
||||
echo -e "Long loop while looking for ASPM word for $1"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function enable_aspm_byte()
|
||||
{
|
||||
device_present $1 present
|
||||
if [[ $? -ne 0 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
find_aspm_byte_address $1
|
||||
if [[ $? -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
ASPM_BYTE_HEX=$(setpci -s $1 ${ASPM_BYTE_ADDRESS}.b)
|
||||
ASPM_BYTE_HEX=$(printf "%X" 0x${ASPM_BYTE_HEX})
|
||||
# setpci doesn't support a mask on the query yet, only on the set,
|
||||
# so to verify a setting on a mask we have no other optoin but
|
||||
# to do do this stuff ourselves.
|
||||
DESIRED_ASPM_BYTE_HEX=$(printf "%X" $(( (0x${ASPM_BYTE_HEX} & ~0x7) |0x${ASPM_SETTING})))
|
||||
|
||||
if [[ $ASPM_BYTE_ADDRESS = "INVALID" ]]; then
|
||||
echo -e "No ASPM byte could be found for $(lspci -s $1)"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$(lspci -s $1)"
|
||||
echo -en "\t${YELLOW}0x${ASPM_BYTE_ADDRESS}${NORMAL} : ${CYAN}0x${ASPM_BYTE_HEX}${GREEN} --> ${BLUE}0x${DESIRED_ASPM_BYTE_HEX}${NORMAL} ... "
|
||||
|
||||
device_present $1 present
|
||||
if [[ $? -ne 0 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# Avoid setting if already set
|
||||
if [[ $ASPM_BYTE_HEX = $DESIRED_ASPM_BYTE_HEX ]]; then
|
||||
echo -e "[${GREEN}SUCESS${NORMAL}] (${GREEN}already set${NORMAL})"
|
||||
aspm_setting_to_string $ASPM_SETTING
|
||||
return 0
|
||||
fi
|
||||
|
||||
# This only writes the last 3 bits
|
||||
setpci -s $1 ${ASPM_BYTE_ADDRESS}.b=${ASPM_SETTING}:3
|
||||
|
||||
sleep 3
|
||||
|
||||
ACTUAL_ASPM_BYTE_HEX=$(setpci -s $1 ${ASPM_BYTE_ADDRESS}.b)
|
||||
ACTUAL_ASPM_BYTE_HEX=$(printf "%X" 0x${ACTUAL_ASPM_BYTE_HEX})
|
||||
|
||||
# Do not retry this if it failed, if it failed to set.
|
||||
# Likey if it failed its a good reason and you should look
|
||||
# into that.
|
||||
if [[ $ACTUAL_ASPM_BYTE_HEX != $DESIRED_ASPM_BYTE_HEX ]]; then
|
||||
echo -e "\t[${RED}FAIL${NORMAL}] (0x${ACTUAL_ASPM_BYTE_HEX})"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "\t[${GREEN}SUCCESS]${NORMAL}]"
|
||||
aspm_setting_to_string $ASPM_SETTING
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
device_present $ENDPOINT not_sure
|
||||
if [[ $? -ne 0 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
enable_aspm_byte $ENDPOINT
|
||||
}
|
||||
|
||||
function enable_aspm_all() {
|
||||
ENDPOINTS=($(lspci | cut -d " " -f 1))
|
||||
for ENDPOINT in "${ENDPOINTS[@]}"; do
|
||||
if lspci -s $ENDPOINT -vnvn | grep -q ASPM; then
|
||||
enable_aspm $ENDPOINT 3
|
||||
else
|
||||
echo -e "${CYAN}$ENDPOINT${NORMAL} doesn't support ASPM"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
enable_aspm_all
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue