aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 22e7e1e..7ce5b9e 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 4e1896e..0f280c7 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 */