Skip to content

Instantly share code, notes, and snippets.

@ThomasKaiser
Created January 31, 2025 11:06
Show Gist options
  • Save ThomasKaiser/2c2bd04539a64a906f5520432a651d1d to your computer and use it in GitHub Desktop.
Save ThomasKaiser/2c2bd04539a64a906f5520432a651d1d to your computer and use it in GitHub Desktop.
set-samsung-speed.sh
#!/bin/bash
#
# script to set link speed of Samsung NVMe SSDs to $1
#
# almost completely based on https://www.alexforencich.com/wiki/en/pcie/set-speed
# (archived at https://archive.ph/dRb6z)
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
setspeed() {
dev=$1
speed=$2
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
dev="0000:$dev"
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
echo "Error: device $dev not found"
exit 1
fi
pciec=$(setpci -s $dev CAP_EXP+02.W)
pt=$((("0x$pciec" & 0xF0) >> 4))
port=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$dev")))
if (($pt == 0)) || (($pt == 1)) || (($pt == 5)); then
dev=$port
fi
lc=$(setpci -s $dev CAP_EXP+0c.L)
ls=$(setpci -s $dev CAP_EXP+12.W)
max_speed=$(("0x$lc" & 0xF))
echo "Link capabilities:" $lc
echo "Max link speed:" $max_speed
echo "Link status:" $ls
echo "Current link speed:" $(("0x$ls" & 0xF))
if [ -z "$speed" ]; then
speed=$max_speed
fi
if (($speed > $max_speed)); then
speed=$max_speed
fi
echo "Configuring $dev..."
lc2=$(setpci -s $dev CAP_EXP+30.L)
echo "Original link control 2:" $lc2
echo "Original link target speed:" $(("0x$lc2" & 0xF))
lc2n=$(printf "%08x" $((("0x$lc2" & 0xFFFFFFF0) | $speed)))
echo "New target link speed:" $speed
echo "New link control 2:" $lc2n
setpci -s $dev CAP_EXP+30.L=$lc2n
echo "Triggering link retraining..."
lc=$(setpci -s $dev CAP_EXP+10.L)
echo "Original link control:" $lc
lcn=$(printf "%08x" $(("0x$lc" | 0x20)))
echo "New link control:" $lcn
setpci -s $dev CAP_EXP+10.L=$lcn
sleep 0.1
ls=$(setpci -s $dev CAP_EXP+12.W)
echo "Link status:" $ls
echo "Current link speed:" $(("0x$ls" & 0xF))
} # setspeed
LinkSpeed="$1"
if [ -z "${LinkSpeed}" ]; then
echo "Error: no link speed specified. Needs to be 1 to 4. Exiting"
exit 1
fi
lspci | awk -F" " '/Samsung/ {print $1}' | while read ; do
setspeed "${REPLY}" ${LinkSpeed} >/dev/null
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment