Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
en:pcie:hot-reset-linux [2019/04/16 23:01]
alex
en:pcie:hot-reset-linux [2020/04/29 07:59] (current)
alex
Line 3: Line 3:
 Resets in PCI express are a bit complex. There are two main types of resets - conventional reset, and function-level reset. There are also two types of conventional resets, fundamental resets and non-fundamental resets. See the PCI express specification for all of the details. Resets in PCI express are a bit complex. There are two main types of resets - conventional reset, and function-level reset. There are also two types of conventional resets, fundamental resets and non-fundamental resets. See the PCI express specification for all of the details.
  
-A 'cold reset' is a fundamental reset that takes place after power is applied to a PCIe device. There appears to be no standard way of triggering a cold reset, save for turning the system off and back on again. On my machines, the /​sys/​bus/​pci/​slots directory is empty.+A 'cold reset' is a fundamental reset that takes place after power is applied to a PCIe device. There appears to be no standard way of triggering a cold reset, save for turning the system off and back on again. On my machines, the ''​/​sys/​bus/​pci/​slots'' ​directory is empty.
  
 A 'warm reset' is a fundamental reset that is triggered without disconnecting power from the device. There appears to be no standard way of triggering a warm reset. A 'warm reset' is a fundamental reset that is triggered without disconnecting power from the device. There appears to be no standard way of triggering a warm reset.
Line 11: Line 11:
 A '​function-level reset' (FLR) is a reset that affects only a single function of a PCI express device. It must not reset the entire PCIe device. Implementing function-level resets is not required by the PCIe specification. A function-level reset is initiated by setting the initiate function-level reset bit in the function'​s device control register in the PCI express capability structure in the PCI configuration space. A '​function-level reset' (FLR) is a reset that affects only a single function of a PCI express device. It must not reset the entire PCIe device. Implementing function-level resets is not required by the PCIe specification. A function-level reset is initiated by setting the initiate function-level reset bit in the function'​s device control register in the PCI express capability structure in the PCI configuration space.
  
-Linux exposes the function-level reset functionality in the form of /​sys/​bus/​pci/​devices/​$dev/​reset. Writing a 1 to this file will initiate a function-level reset on the corresponding function. Note that this only affects that specific function of the device, not the whole device, and devices are not required to implement function-level resets as per the PCIe specification.+Linux exposes the function-level reset functionality in the form of ''​/​sys/​bus/​pci/​devices/​$dev/​reset''​. Writing a 1 to this file will initiate a function-level reset on the corresponding function. Note that this only affects that specific function of the device, not the whole device, and devices are not required to implement function-level resets as per the PCIe specification.
  
 I am not aware of any '​nice'​ method for triggering a hot reset (there is no sysfs entry for that). However, it is possible to use setpci to do so with the following script: I am not aware of any '​nice'​ method for triggering a hot reset (there is no sysfs entry for that). However, it is possible to use setpci to do so with the following script:
  
-<code sh>+<​code ​bash pcie_hot_reset.sh>
  
 #!/bin/bash #!/bin/bash
Line 25: Line 25:
     exit 1     exit 1
 fi 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 [ ! -e "/​sys/​bus/​pci/​devices/​$port"​ ]; then
 +    echo "​Error:​ device $port not found"
 +    exit 1
 +fi
 +
 +echo "​Removing $dev..."​
 +
 +echo 1 > "/​sys/​bus/​pci/​devices/​$dev/​remove"​
 +
 +echo "​Performing hot reset of port $port..."​
 +
 +bc=$(setpci -s $port BRIDGE_CONTROL)
 +
 +echo "​Bridge control:"​ $bc
 +
 +setpci -s $port BRIDGE_CONTROL=$(printf "​%04x"​ $(("​0x$bc"​ | 0x40)))
 +sleep 0.01
 +setpci -s $port BRIDGE_CONTROL=$bc
 +sleep 0.5
 +
 +echo "​Rescanning bus..."​
 +
 +echo 1 > "/​sys/​bus/​pci/​devices/​$port/​rescan"​
  
 </​code>​ </​code>​
Line 30: Line 65:
 Ensure that all attached drivers are unloaded before running this script. This script will attempt to remove the PCIe device, then command the upstream switch port to issue a hot reset, then attempt to rescan the PCIe bus. This script has also only been tested on devices with a single function, so it may need some reworking for devices with multiple functions. ​ Ensure that all attached drivers are unloaded before running this script. This script will attempt to remove the PCIe device, then command the upstream switch port to issue a hot reset, then attempt to rescan the PCIe bus. This script has also only been tested on devices with a single function, so it may need some reworking for devices with multiple functions. ​
  
 +[[https://​unix.stackexchange.com/​a/​474378/​55879|Answer on Stack Exchange]]