diff options
-rw-r--r-- | src/drivers/net/ena.c | 93 | ||||
-rw-r--r-- | src/drivers/net/ena.h | 46 |
2 files changed, 139 insertions, 0 deletions
diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 22e7e1e30..7ce5b9eb9 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 4e1896e86..0f280c700 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 */ |