summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Graf <graf@amazon.com>2023-01-16 21:56:53 +0000
committerMichael Brown <mcb30@ipxe.org>2023-01-18 22:47:58 +0000
commit6b977d1250e497abd357cca863140361472a6082 (patch)
tree82f433ac41fbd5ccf39aaca9f723fa0401d3e5ac
parent08740220baba87cbc6acb1c00cd5b492ac0c5a08 (diff)
downloadqemu-ipxe-aenq.tar.gz
[ena] Allocate an unused Asynchronous Event Notification Queue (AENQ)aenq
We currently don't allocate an Asynchronous Event Notification Queue (AENQ) because we don't actually care about any of the events that may come in. The ENA firmware found on Graviton instances requires the AENQ to exist, otherwise all admin queue commands will fail. Fix by allocating an AENQ and disabling all events (so that we do not need to include code to acknowledge any events that may arrive). Signed-off-by: Alexander Graf <graf@amazon.com>
-rw-r--r--src/drivers/net/ena.c93
-rw-r--r--src/drivers/net/ena.h46
2 files changed, 139 insertions, 0 deletions
diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c
index 22e7e1e3..7ce5b9eb 100644
--- a/src/drivers/net/ena.c
+++ b/src/drivers/net/ena.c
@@ -351,6 +351,90 @@ static int ena_admin ( struct ena_nic *ena, union ena_aq_req *req,
}
/**
+ * Set async event notification queue config
+ *
+ * @v ena ENA device
+ * @v enabled Bitmask of the groups to enable
+ * @ret rc Return status code
+ */
+static int ena_set_aenq_config ( struct ena_nic *ena, uint32_t enabled ) {
+ union ena_aq_req *req;
+ union ena_acq_rsp *rsp;
+ union ena_feature *feature;
+ int rc;
+
+ /* Construct request */
+ req = ena_admin_req ( ena );
+ req->header.opcode = ENA_SET_FEATURE;
+ req->set_feature.id = ENA_AENQ_CONFIG;
+ feature = &req->set_feature.feature;
+ feature->aenq.enabled = cpu_to_le32 ( enabled );
+
+ /* Issue request */
+ if ( ( rc = ena_admin ( ena, req, &rsp ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Create async event notification queue
+ *
+ * @v ena ENA device
+ * @ret rc Return status code
+ */
+static int ena_create_async ( struct ena_nic *ena ) {
+ size_t aenq_len = ( ENA_AENQ_COUNT * sizeof ( ena->aenq.evt[0] ) );
+ int rc;
+
+ /* Allocate async event notification queue */
+ ena->aenq.evt = malloc_phys ( aenq_len, aenq_len );
+ if ( ! ena->aenq.evt ) {
+ rc = -ENOMEM;
+ goto err_alloc_aenq;
+ }
+ memset ( ena->aenq.evt, 0, aenq_len );
+
+ /* Program queue address and capabilities */
+ ena_set_base ( ena, ENA_AENQ_BASE, ena->aenq.evt );
+ ena_set_caps ( ena, ENA_AENQ_CAPS, ENA_AENQ_COUNT,
+ sizeof ( ena->aenq.evt[0] ) );
+
+ DBGC ( ena, "ENA %p AENQ [%08lx,%08lx)\n",
+ ena, virt_to_phys ( ena->aenq.evt ),
+ ( virt_to_phys ( ena->aenq.evt ) + aenq_len ) );
+
+ /* Disable all events */
+ if ( ( rc = ena_set_aenq_config ( ena, 0 ) ) != 0 )
+ goto err_set_aenq_config;
+
+ return 0;
+
+ err_set_aenq_config:
+ ena_clear_caps ( ena, ENA_AENQ_CAPS );
+ free_phys ( ena->aenq.evt, aenq_len );
+ err_alloc_aenq:
+ return rc;
+}
+
+/**
+ * Destroy async event notification queue
+ *
+ * @v ena ENA device
+ */
+static void ena_destroy_async ( struct ena_nic *ena ) {
+ size_t aenq_len = ( ENA_AENQ_COUNT * sizeof ( ena->aenq.evt[0] ) );
+
+ /* Clear queue capabilities */
+ ena_clear_caps ( ena, ENA_AENQ_CAPS );
+ wmb();
+
+ /* Free queue */
+ free_phys ( ena->aenq.evt, aenq_len );
+ DBGC ( ena, "ENA %p AENQ destroyed\n", ena );
+}
+
+/**
* Create submission queue
*
* @v ena ENA device
@@ -1098,6 +1182,10 @@ static int ena_probe ( struct pci_device *pci ) {
if ( ( rc = ena_create_admin ( ena ) ) != 0 )
goto err_create_admin;
+ /* Create async event notification queue */
+ if ( ( rc = ena_create_async ( ena ) ) != 0 )
+ goto err_create_async;
+
/* Set host attributes */
if ( ( rc = ena_set_host_attributes ( ena ) ) != 0 )
goto err_set_host_attributes;
@@ -1121,6 +1209,8 @@ static int ena_probe ( struct pci_device *pci ) {
err_register_netdev:
err_get_device_attributes:
err_set_host_attributes:
+ ena_destroy_async ( ena );
+ err_create_async:
ena_destroy_admin ( ena );
err_create_admin:
ena_reset ( ena );
@@ -1148,6 +1238,9 @@ static void ena_remove ( struct pci_device *pci ) {
/* Unregister network device */
unregister_netdev ( netdev );
+ /* Destroy async event notification queue */
+ ena_destroy_async ( ena );
+
/* Destroy admin queues */
ena_destroy_admin ( ena );
diff --git a/src/drivers/net/ena.h b/src/drivers/net/ena.h
index 4e1896e8..0f280c70 100644
--- a/src/drivers/net/ena.h
+++ b/src/drivers/net/ena.h
@@ -24,6 +24,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Number of admin completion queue entries */
#define ENA_ACQ_COUNT 2
+/** Number of async event notification queue entries */
+#define ENA_AENQ_COUNT 2
+
/** Number of transmit queue entries */
#define ENA_TX_COUNT 16
@@ -60,6 +63,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Maximum time to wait for admin requests */
#define ENA_ADMIN_MAX_WAIT_MS 5000
+/** Async event notification queue capabilities register */
+#define ENA_AENQ_CAPS 0x34
+
+/** Async event notification queue base address register */
+#define ENA_AENQ_BASE 0x38
+
/** Device control register */
#define ENA_CTRL 0x54
#define ENA_CTRL_RESET 0x00000001UL /**< Reset */
@@ -130,6 +139,17 @@ struct ena_device_attributes {
uint32_t mtu;
} __attribute__ (( packed ));
+/** Async event notification queue config */
+#define ENA_AENQ_CONFIG 26
+
+/** Async event notification queue config */
+struct ena_aenq_config {
+ /** Bitmask of supported AENQ groups (device -> host) */
+ uint32_t supported;
+ /** Bitmask of enabled AENQ groups (host -> device) */
+ uint32_t enabled;
+} __attribute__ (( packed ));
+
/** Host attributes */
#define ENA_HOST_ATTRIBUTES 28
@@ -208,6 +228,8 @@ struct ena_host_info {
union ena_feature {
/** Device attributes */
struct ena_device_attributes device;
+ /** Async event notification queue config */
+ struct ena_aenq_config aenq;
/** Host attributes */
struct ena_host_attributes host;
};
@@ -506,6 +528,28 @@ struct ena_acq {
unsigned int phase;
};
+/** Async event notification queue event */
+struct ena_aenq_event {
+ /** Type of event */
+ uint16_t group;
+ /** ID of event */
+ uint16_t syndrome;
+ /** Phase */
+ uint8_t flags;
+ /** Reserved */
+ uint8_t reserved[3];
+ /** Timestamp */
+ uint64_t timestamp;
+ /** Additional event data */
+ uint8_t data[48];
+} __attribute__ (( packed ));
+
+/** Async event notification queue */
+struct ena_aenq {
+ /** Events */
+ struct ena_aenq_event *evt;
+};
+
/** Transmit submission queue entry */
struct ena_tx_sqe {
/** Length */
@@ -702,6 +746,8 @@ struct ena_nic {
struct ena_aq aq;
/** Admin completion queue */
struct ena_acq acq;
+ /** Async event notification queue */
+ struct ena_aenq aenq;
/** Transmit queue */
struct ena_qp tx;
/** Receive queue */