aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-11-01 22:03:34 +0000
committerMichael Brown <mcb30@ipxe.org>2023-11-01 22:32:21 +0000
commitf883203132b3d06ffb354f1b11d1f65a0c70ff42 (patch)
tree64f7c412a733a8923327a9e37534a633a69dbe6d
parent115707c0edebad65f87525fed583fef73880016d (diff)
downloadipxe-f883203132b3d06ffb354f1b11d1f65a0c70ff42.zip
ipxe-f883203132b3d06ffb354f1b11d1f65a0c70ff42.tar.gz
ipxe-f883203132b3d06ffb354f1b11d1f65a0c70ff42.tar.bz2
[pci] Force completion of ECAM configuration space writes
The PCIe specification requires that "processor and host bridge implementations must ensure that a method exists for the software to determine when the write using the ECAM is completed by the completer" but does not specify any particular method to be used. Some platforms might treat writes to the ECAM region as non-posted, others might require reading back from a dedicated (and implementation-specific) completion register to determine when the configuration space write has completed. Since PCI configuration space writes will never be used for any performance-critical datapath operations (on any sane hardware), a simple and platform-independent solution is to always read back from the written register in order to guarantee that the write must have completed. This is safe to do, since the PCIe specification defines a limited set of configuration register types, none of which have read side effects. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/drivers/bus/ecam.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c
index 1d57bd2..376f349 100644
--- a/src/drivers/bus/ecam.c
+++ b/src/drivers/bus/ecam.c
@@ -235,7 +235,7 @@ int ecam_write ( struct pci_device *pci, unsigned int location,
if ( ( rc = ecam_access ( pci ) ) != 0 )
return rc;
- /* Read from address */
+ /* Write to address */
index = ( pci->busdevfn - ecam.range.start );
addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
switch ( len ) {
@@ -252,6 +252,15 @@ int ecam_write ( struct pci_device *pci, unsigned int location,
assert ( 0 );
}
+ /* Read from address, to guarantee completion of the write
+ *
+ * PCIe configuration space registers may not have read side
+ * effects. Reading back is therefore always safe to do, and
+ * guarantees that the write has reached the device.
+ */
+ mb();
+ ecam_read ( pci, location, &value );
+
return 0;
}