aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2021-02-13 18:55:39 +0000
committerMichael Brown <mcb30@ipxe.org>2021-02-13 19:08:45 +0000
commit0049243367e50ccfbc66611716ec3b96b6ab95b5 (patch)
treef9de127991187dd1a154984d5e1114571cb9b176
parentc160fb259378e5f08190db39b5bf4f697f892e7c (diff)
downloadipxe-0049243367e50ccfbc66611716ec3b96b6ab95b5.zip
ipxe-0049243367e50ccfbc66611716ec3b96b6ab95b5.tar.gz
ipxe-0049243367e50ccfbc66611716ec3b96b6ab95b5.tar.bz2
[ena] Switch to two-phase reset mechanism
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>
-rw-r--r--src/drivers/net/ena.c40
-rw-r--r--src/drivers/net/ena.h2
2 files changed, 33 insertions, 9 deletions
diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c
index 12c1615..85da1c0 100644
--- a/src/drivers/net/ena.c
+++ b/src/drivers/net/ena.c
@@ -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
diff --git a/src/drivers/net/ena.h b/src/drivers/net/ena.h
index 0496fc6..676c5b8 100644
--- a/src/drivers/net/ena.h
+++ b/src/drivers/net/ena.h
@@ -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 {