summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2009-10-14 03:09:49 +0200
committerMichael Brown2009-10-14 03:11:16 +0200
commit9f7141a1cedeca6d55b9ce43322f509a4577c883 (patch)
treee2a90b24905305267a83904747643ebec171191d
parent[pci] Add generic configuration space backup/restore facility (diff)
downloadipxe-9f7141a1cedeca6d55b9ce43322f509a4577c883.tar.gz
ipxe-9f7141a1cedeca6d55b9ce43322f509a4577c883.tar.xz
ipxe-9f7141a1cedeca6d55b9ce43322f509a4577c883.zip
[hermon] Reset device during probe()
Some systems will retry their boot sequence in the event of a boot failure. On these systems, the second and subsequent boot attempts will fail to initialise the Hermon HCA. Fix by resetting the HCA during probe(). This incurs a one-second cost, but there seems to be no viable alternative. Originally-fixed-by: Itay Gazit <itaygazit@gmail.com>
-rw-r--r--src/drivers/infiniband/hermon.c23
-rw-r--r--src/drivers/infiniband/hermon.h5
2 files changed, 28 insertions, 0 deletions
diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c
index bff128fd..b9c97f94 100644
--- a/src/drivers/infiniband/hermon.c
+++ b/src/drivers/infiniband/hermon.c
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <byteswap.h>
#include <gpxe/io.h>
#include <gpxe/pci.h>
+#include <gpxe/pcibackup.h>
#include <gpxe/malloc.h>
#include <gpxe/umalloc.h>
#include <gpxe/iobuf.h>
@@ -2551,6 +2552,25 @@ static int hermon_configure_special_qps ( struct hermon *hermon ) {
}
/**
+ * Reset device
+ *
+ * @v hermon Hermon device
+ * @v pci PCI device
+ */
+static void hermon_reset ( struct hermon *hermon,
+ struct pci_device *pci ) {
+ struct pci_config_backup backup;
+ static const uint8_t backup_exclude[] =
+ PCI_CONFIG_BACKUP_EXCLUDE ( 0x58, 0x5c );
+
+ 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 );
+}
+
+/**
* Probe PCI device
*
* @v pci PCI device
@@ -2582,6 +2602,9 @@ static int hermon_probe ( struct pci_device *pci,
hermon->uar = ioremap ( pci_bar_start ( pci, HERMON_PCI_UAR_BAR ),
HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE );
+ /* Reset device */
+ hermon_reset ( hermon, pci );
+
/* Allocate space for mailboxes */
hermon->mailbox_in = malloc_dma ( HERMON_MBOX_SIZE,
HERMON_MBOX_ALIGN );
diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h
index f19fd359..c53f3da5 100644
--- a/src/drivers/infiniband/hermon.h
+++ b/src/drivers/infiniband/hermon.h
@@ -29,6 +29,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define HERMON_PCI_CONFIG_BAR_SIZE 0x100000
#define HERMON_PCI_UAR_BAR PCI_BASE_ADDRESS_2
+/* Device reset */
+#define HERMON_RESET_OFFSET 0x0f0010
+#define HERMON_RESET_MAGIC 0x01000000UL
+#define HERMON_RESET_WAIT_TIME_MS 1000
+
/* Work queue entry and completion queue entry opcodes */
#define HERMON_OPCODE_NOP 0x00
#define HERMON_OPCODE_SEND 0x0a