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.
#!/bin/bash dev=$1 if [ -z "$dev" ]; then echo "Error: no device specified" exit 1 fi 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 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" 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) | 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