[hermon] Reset device during probe()
authorMichael Brown <mcb30@etherboot.org>
Wed, 14 Oct 2009 01:09:49 +0000 (02:09 +0100)
committerMichael Brown <mcb30@etherboot.org>
Wed, 14 Oct 2009 01:11:16 +0000 (02:11 +0100)
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>
src/drivers/infiniband/hermon.c
src/drivers/infiniband/hermon.h

index bff128f..b9c97f9 100644 (file)
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <byteswap.h>
 #include <gpxe/io.h>
 #include <gpxe/pci.h>
 #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>
 #include <gpxe/malloc.h>
 #include <gpxe/umalloc.h>
 #include <gpxe/iobuf.h>
@@ -2550,6 +2551,25 @@ static int hermon_configure_special_qps ( struct hermon *hermon ) {
        return 0;
 }
 
        return 0;
 }
 
+/**
+ * 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
  *
 /**
  * Probe 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 );
 
        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 );
        /* Allocate space for mailboxes */
        hermon->mailbox_in = malloc_dma ( HERMON_MBOX_SIZE,
                                          HERMON_MBOX_ALIGN );
index f19fd35..c53f3da 100644 (file)
@@ -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
 
 #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
 /* Work queue entry and completion queue entry opcodes */
 #define HERMON_OPCODE_NOP              0x00
 #define HERMON_OPCODE_SEND             0x0a