aboutsummaryrefslogtreecommitdiffstats
path: root/src/drivers/infiniband/hermon.c
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2021-02-01 22:25:52 +0000
committerMichael Brown <mcb30@ipxe.org>2021-02-01 22:29:30 +0000
commit410566cef7b760b5e59050b38e1eb4e7572f059b (patch)
treecc1db725f32bc3457702debb9a93e20a74564d4c /src/drivers/infiniband/hermon.c
parent7b2b35981f862ba17765c87f657353f93b5b41d4 (diff)
downloadipxe-410566cef7b760b5e59050b38e1eb4e7572f059b.tar.gz
[hermon] Minimise reset time
Check for reset completion by waiting for the device to respond to PCI configuration cycles, as documented in the Programmer's Reference Manual. On the original ConnectX HCA, this reduces the time spent on reset from 1000ms down to 1ms. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/infiniband/hermon.c')
-rw-r--r--src/drivers/infiniband/hermon.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c
index 35326ac6e..d13a14678 100644
--- a/src/drivers/infiniband/hermon.c
+++ b/src/drivers/infiniband/hermon.c
@@ -2792,22 +2792,45 @@ static void hermon_unmap_icm ( struct hermon *hermon ) {
* Reset device
*
* @v hermon Hermon device
+ * @ret rc Return status code
*/
-static void hermon_reset ( struct hermon *hermon ) {
+static int hermon_reset ( struct hermon *hermon ) {
struct pci_device *pci = hermon->pci;
struct pci_config_backup backup;
static const uint8_t backup_exclude[] =
PCI_CONFIG_BACKUP_EXCLUDE ( 0x58, 0x5c );
+ uint16_t vendor;
+ unsigned int i;
+
+ /* Reset command interface toggle */
+ hermon->toggle = 0;
/* Perform device reset and preserve PCI configuration */
pci_backup ( pci, &backup, backup_exclude );
writel ( HERMON_RESET_MAGIC,
( hermon->config + HERMON_RESET_OFFSET ) );
- mdelay ( HERMON_RESET_WAIT_TIME_MS );
- pci_restore ( pci, &backup, backup_exclude );
- /* Reset command interface toggle */
- hermon->toggle = 0;
+ /* Wait until device starts responding to configuration cycles */
+ for ( i = 0 ; i < HERMON_RESET_MAX_WAIT_MS ; i++ ) {
+
+ /* Read PCI vendor ID */
+ pci_read_config_word ( pci, PCI_VENDOR_ID, &vendor );
+ if ( vendor == pci->vendor ) {
+
+ /* Restore PCI configuration */
+ pci_restore ( pci, &backup, backup_exclude );
+
+ DBGC ( hermon, "Hermon %p reset after %dms\n",
+ hermon, i );
+ return 0;
+ }
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( hermon, "Hermon %p timed out waiting for reset\n", hermon );
+ return -ETIMEDOUT;
}
/**
@@ -3967,7 +3990,8 @@ static int hermon_probe ( struct pci_device *pci ) {
HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE );
/* Reset device */
- hermon_reset ( hermon );
+ if ( ( rc = hermon_reset ( hermon ) ) != 0 )
+ goto err_reset;
/* Start firmware */
if ( ( rc = hermon_start_firmware ( hermon ) ) != 0 )
@@ -4060,6 +4084,7 @@ static int hermon_probe ( struct pci_device *pci ) {
err_get_cap:
hermon_stop_firmware ( hermon );
err_start_firmware:
+ err_reset:
iounmap ( hermon->uar );
iounmap ( hermon->config );
hermon_free ( hermon );