Reset a device
#include <pci/pci.h> pci_err_t pci_device_reset( pci_devhdl_t hdl, pci_resetType_e resetType );
A reset type that's less than pci_resetType_e_BUS is considered to mean no reset (a no-op).
A reset type that's greater than pci_resetType_e_FUNCTION is considered to be a hardware-specific reset. The behavior of hardware-specific resets, if supported, is defined by the hardware-dependent module. Refer to the release notes or the usage information in the hardware-dependent module applicable to your platform for details.
The pci_device_reset() function initiates a reset of a specific device (function-level reset if the device is PCIe and supports FLR as determined by the device capabilities register or if the device is PCI and supports the Advanced Features capability and FLR as per the AF capabilities register) or of a PCI bus segment/PCIe link (secondary bus reset) if the device is a PCI-to-PCI bridge or PCIe Root Port that reports as a PCI-to-PCI bridge.
The hdl arguments identifies the specific device to be reset, or the bus or link on which the device resides.
The primary types of reset are:
In both cases, you must be an owner of the device identified by hdl and the only remaining attacher.
Affected devices
For a function reset, only the device identified by hdl is reset. This includes a specific function of a multifunction device. You must be an owner of the device and the only remaining attacher (all other multiowned attachers, if any, must have detached). In addition, for bus/link resets, all devices that reside on the same bus/link as the device identified by hdl or that reside on a bus/link that's downstream of the bus/link on which the device identified by hdl resides are also reset. In this case, those devices must not have any attachments (i.e., no other software must have successfully called pci_device_attach() on these devices without having called pci_device_detach() prior to the reset operation). It's the responsibility of the application software to coordinate these operations for other affected device software, or the pci_device_reset() call will fail.
A reset of a specific device (i.e., a BDF) is supported by the PCI specification-defined Function Level Reset (FLR) mechanism. In order to initiate this type of reset, the device must either be a PCIe endpoint with bit 28 of the device capabilities register set to binary value 1 or have the Advanced Features (AF) capability with bit 1 of the AF capabilities register set to binary value 1, otherwise this reset is unsupported.
Other reset types are allowed, but these have no defined behavior within the PCI server, and so are passed directly to the hardware-dependent module. This allows for platform-specific reset processing to be accommodated. It's the responsibility of the hardware-dependent module to document what additional reset types if any it supports and what the behaviors of those resets are.
Although the hardware-dependent module has complete control over the reset behavior, the PCI server ensures that configuration space accesses to the device being reset are halted, and after reset, that the device is configured into the D0-initialized state unless otherwise prevented from doing so by the hardware-dependent module. All of the discussions that follow regarding post-reset state and interrupts are applicable to hardware-dependent reset types unless the hardware-dependent module documents otherwise.
Post-reset driver state
On return from a successful pci_device_reset(), your hdl is still valid, as are any mappings to address spaces obtained with a successful call to pci_device_read_ba(), but all capabilities are disabled. In order to use the capabilities, you need to:
Device software for other affected devices (if any), must go through the entire initialization phase starting with pci_device_attach(), because they were required to detach in order for the reset to take place.
Regarding interrupts
If the device was configured to use the MSI or MSI-X capability, the IRQs associated with the MSI/MSI-X vectors are released when the capability is disabled. Since MSI/MSI-X vectors are allocated when the capability is enabled, and these could potentially change between the disabling and reenabling of these capabilities, driver software should call InterruptDetach() for previously assigned IRQs, reread them with pci_device_read_irq(), and then reattach them with InterruptAttach() or InterruptAttachEvent().
If you aren't using MSI or MSI-X, you don't need to reread the pin-based IRQs originally returned because they don't change. That is, there's no need for the driver software to call InterruptDetach(), pci_device_read_irq(), and then InterruptAttach() or InterruptAttachEvent() after the reset if using pin-based (i.e., non-MSI or non-MSI-X) interrupts.
If successful, a call to pci_device_reset() with a reset type of either pci_resetType_e_BUS or pci_resetType_e_FUNCTION returns PCI_ERR_OK, and all affected devices (as described above) have been reset and reconfigured to the D0-initialized state. Any driver software using those device must comprehend this condition and perform any required device-specific initialization that may have been lost as a result of the reset operation.
For reset types other than pci_resetType_e_BUS or pci_resetType_e_FUNCTION, the hardware-dependent module must document the post-reset state of affected devices.
If any error occurs, pci_device_reset() returns one of the following values, and you should consider all affected devices (as outlined above) to be in an unknown and unusable state. It this situation, it may be possible, and even desirable to reissue the reset command.
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | No |
Signal handler | No |
Thread | Yes |