]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[ena] Switch to two-phase reset mechanism
authorMichael Brown <mcb30@ipxe.org>
Sat, 13 Feb 2021 18:55:39 +0000 (18:55 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sat, 13 Feb 2021 19:08:45 +0000 (19:08 +0000)
The Linux and FreeBSD drivers for the (totally undocumented) ENA
adapters use a two-phase reset mechanism: first set ENA_CTRL.RESET and
wait for this to be reflected in ENA_STAT.RESET, then clear
ENA_CTRL.RESET and again wait for it to be reflected in
ENA_STAT.RESET.

The iPXE driver currently assumes a self-clearing reset mechanism,
which appeared to work at the time that the driver was created but
seems no longer to function, at least on the t3.nano and t3a.nano
instance types found in eu-west-1.

Switch to a simplified version of the two-phase reset mechanism as
used by Linux and FreeBSD.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/net/ena.c
src/drivers/net/ena.h

index 12c161522ea8f8bed4c86ed76650985d670e0a36..85da1c090c63bb9e901855c6bcc79cfbfa48dc41 100644 (file)
@@ -65,35 +65,59 @@ static const char * ena_direction ( unsigned int direction ) {
  */
 
 /**
- * Reset hardware
+ * Wait for reset operation to be acknowledged
  *
  * @v ena              ENA device
+ * @v expected         Expected reset state
  * @ret rc             Return status code
  */
-static int ena_reset ( struct ena_nic *ena ) {
+static int ena_reset_wait ( struct ena_nic *ena, uint32_t expected ) {
        uint32_t stat;
        unsigned int i;
 
-       /* Trigger reset */
-       writel ( ENA_CTRL_RESET, ( ena->regs + ENA_CTRL ) );
-
        /* Wait for reset to complete */
        for ( i = 0 ; i < ENA_RESET_MAX_WAIT_MS ; i++ ) {
 
                /* Check if device is ready */
                stat = readl ( ena->regs + ENA_STAT );
-               if ( stat & ENA_STAT_READY )
+               if ( ( stat & ENA_STAT_RESET ) == expected )
                        return 0;
 
                /* Delay */
                mdelay ( 1 );
        }
 
-       DBGC ( ena, "ENA %p timed out waiting for reset (status %#08x)\n",
-              ena, stat );
+       DBGC ( ena, "ENA %p timed out waiting for reset status %#08x "
+              "(got %#08x)\n", ena, expected, stat );
        return -ETIMEDOUT;
 }
 
+/**
+ * Reset hardware
+ *
+ * @v ena              ENA device
+ * @ret rc             Return status code
+ */
+static int ena_reset ( struct ena_nic *ena ) {
+       int rc;
+
+       /* Trigger reset */
+       writel ( ENA_CTRL_RESET, ( ena->regs + ENA_CTRL ) );
+
+       /* Wait for reset to take effect */
+       if ( ( rc = ena_reset_wait ( ena, ENA_STAT_RESET ) ) != 0 )
+               return rc;
+
+       /* Clear reset */
+       writel ( 0, ( ena->regs + ENA_CTRL ) );
+
+       /* Wait for reset to clear */
+       if ( ( rc = ena_reset_wait ( ena, 0 ) ) != 0 )
+               return rc;
+
+       return 0;
+}
+
 /******************************************************************************
  *
  * Admin queue
index 0496fc6bd6580f87af50999ddb37e5e5f7c2e6af..676c5b87876b0f10fe67227dcab989afd7effad9 100644 (file)
@@ -66,7 +66,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 /** Device status register */
 #define ENA_STAT 0x58
-#define ENA_STAT_READY 0x00000001UL    /**< Ready */
+#define ENA_STAT_RESET 0x00000008UL    /**< Reset in progress */
 
 /** Admin queue entry header */
 struct ena_aq_header {