return rc;
}
+/**
+ * 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
*
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;
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 );
/* Unregister network device */
unregister_netdev ( netdev );
+ /* Destroy async event notification queue */
+ ena_destroy_async ( ena );
+
/* Destroy admin queues */
ena_destroy_admin ( ena );
/** 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
/** 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 */
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
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;
};
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 */
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 */