PCIe Force Gen 2

This script uses setpci to force a device to fall back from gen 3 to gen 2 link rate. This can be useful when using a PCIe protocol analyzer that does not support PCIe gen 3. It may be necessary to run this script on the switch or root port upstream of the device.

if [ -z "$dev" ]; then
    echo "Error: no device specified"
    exit 1
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
    echo "Error: device $dev not found"
    exit 1
port=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$dev")))
if [[ $port != pci* ]]; then
    echo "Note: it may be necessary to run this on the corresponding upstream port"
    echo "Device $dev is connected to upstream port $port"
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) | 0x2)))
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