Skip to content

Instantly share code, notes, and snippets.

@baybal
Last active August 30, 2025 23:56
Show Gist options
  • Save baybal/b499fc5811a7073df0c03ab8da4be904 to your computer and use it in GitHub Desktop.
Save baybal/b499fc5811a7073df0c03ab8da4be904 to your computer and use it in GitHub Desktop.

Revisions

  1. baybal revised this gist May 26, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion aspm_dell9360.sh
    Original file line number Diff line number Diff line change
    @@ -117,7 +117,7 @@ MAX_SEARCH=20
    SEARCH_COUNT=1
    ASPM_BYTE_ADDRESS="INVALID"

    ROOT_PRESENT=$(lspci | grep -c "$ROOT_COMPLEXT")
    ROOT_PRESENT=$(lspci | grep -c "$ROOT_COMPLEX")
    ENDPOINT_PRESENT=$(lspci | grep -c "$ENDPOINT")

    if [[ $(id -u) != 0 ]]; then
  2. baybal revised this gist Apr 16, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion aspm_dell9360.sh
    Original file line number Diff line number Diff line change
    @@ -175,7 +175,7 @@ function find_aspm_byte_address()
    break
    fi

    SEARCH=$(echo "obase=16; ibase=16; $SEARCH + 1" | bc)
    SEARCH=$(echo "obase=16; ibase=16; $SEARCH_UPPER + 1" | bc)
    SEARCH=$(setpci -s $1 ${SEARCH}.b)

    let SEARCH_COUNT=$SEARCH_COUNT+1
  3. baybal created this gist Sep 3, 2018.
    275 changes: 275 additions & 0 deletions aspm_dell9360.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,275 @@
    #!/bin/bash
    # Copyright (c) 2010-2013 Luis R. Rodriguez <[email protected]>
    #
    # 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

    # You just need to modify these three values:

    ENDPOINT="00:1c.5"
    ROOT_COMPLEX="00:1c.4"

    # 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
    ASPM_SETTING=3

    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 <[email protected]>

    # 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=20
    SEARCH_COUNT=1
    ASPM_BYTE_ADDRESS="INVALID"

    ROOT_PRESENT=$(lspci | grep -c "$ROOT_COMPLEXT")
    ENDPOINT_PRESENT=$(lspci | grep -c "$ENDPOINT")

    if [[ $(id -u) != 0 ]]; then
    echo "This needs to be run as root"
    exit 1
    fi

    if [[ $ROOT_PRESENT -eq 0 ]]; then
    echo "Root complex $ROOT_COMPLEX is not present"
    exit
    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)

    let SEARCH_COUNT=$SEARCH_COUNT+1
    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

    echo -e "${CYAN}Root complex${NORMAL}:"
    ROOT_COMPLEX="00:1c.0"
    enable_aspm_byte $ROOT_COMPLEX
    ROOT_COMPLEX="00:1c.4"
    enable_aspm_byte $ROOT_COMPLEX
    ROOT_COMPLEX="00:1c.5"
    enable_aspm_byte $ROOT_COMPLEX
    ROOT_COMPLEX="00:1d.0"
    enable_aspm_byte $ROOT_COMPLEX
    echo

    echo -e "${CYAN}Endpoint${NORMAL}:"
    ENDPOINT="3a:00.0"
    enable_aspm_byte $ENDPOINT
    ENDPOINT="3b:00.0"
    enable_aspm_byte $ENDPOINT
    ENDPOINT="3c:00.0"
    enable_aspm_byte $ENDPOINT
    echo