Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[intelxl] Allow admin queues to be reinitialised
A virtual function reset is triggered via an admin queue command and
will reset the admin queue configuration registers.  Allow the admin
queues to be reinitialised after such a reset, without requiring the
overhead (and potential failure paths) of freeing and reallocating the
queues.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Apr 27, 2019
1 parent 8f3e648 commit 7b68c31
Showing 1 changed file with 85 additions and 41 deletions.
126 changes: 85 additions & 41 deletions src/drivers/net/intelxl.c
Expand Up @@ -45,6 +45,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

static void intelxl_reopen_admin ( struct intelxl_nic *intelxl );

/******************************************************************************
*
* Device reset
Expand Down Expand Up @@ -133,26 +135,47 @@ static const struct intelxl_admin_offsets intelxl_admin_offsets = {
};

/**
* Create admin queue
* Allocate admin queue
*
* @v intelxl Intel device
* @v admin Admin queue
* @ret rc Return status code
*/
static int intelxl_create_admin ( struct intelxl_nic *intelxl,
struct intelxl_admin *admin ) {
static int intelxl_alloc_admin ( struct intelxl_nic *intelxl,
struct intelxl_admin *admin ) {
size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC );
size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
const struct intelxl_admin_offsets *regs = admin->regs;
void *admin_regs = ( intelxl->regs + admin->base );
physaddr_t address;

/* Allocate admin queue */
admin->buf = malloc_dma ( ( buf_len + len ), INTELXL_ALIGN );
if ( ! admin->buf )
return -ENOMEM;
admin->desc = ( ( ( void * ) admin->buf ) + buf_len );

DBGC ( intelxl, "INTELXL %p A%cQ is at [%08llx,%08llx) buf "
"[%08llx,%08llx)\n", intelxl,
( ( admin == &intelxl->command ) ? 'T' : 'R' ),
( ( unsigned long long ) virt_to_bus ( admin->desc ) ),
( ( unsigned long long ) ( virt_to_bus ( admin->desc ) + len ) ),
( ( unsigned long long ) virt_to_bus ( admin->buf ) ),
( ( unsigned long long ) ( virt_to_bus ( admin->buf ) +
buf_len ) ) );
return 0;
}

/**
* Enable admin queue
*
* @v intelxl Intel device
* @v admin Admin queue
*/
static void intelxl_enable_admin ( struct intelxl_nic *intelxl,
struct intelxl_admin *admin ) {
size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
const struct intelxl_admin_offsets *regs = admin->regs;
void *admin_regs = ( intelxl->regs + admin->base );
physaddr_t address;

/* Initialise admin queue */
memset ( admin->desc, 0, len );

Expand All @@ -177,33 +200,33 @@ static int intelxl_create_admin ( struct intelxl_nic *intelxl,
writel ( ( INTELXL_ADMIN_LEN_LEN ( INTELXL_ADMIN_NUM_DESC ) |
INTELXL_ADMIN_LEN_ENABLE ),
admin_regs + regs->len );

DBGC ( intelxl, "INTELXL %p A%cQ is at [%08llx,%08llx) buf "
"[%08llx,%08llx)\n", intelxl,
( ( admin == &intelxl->command ) ? 'T' : 'R' ),
( ( unsigned long long ) address ),
( ( unsigned long long ) address + len ),
( ( unsigned long long ) virt_to_bus ( admin->buf ) ),
( ( unsigned long long ) ( virt_to_bus ( admin->buf ) +
buf_len ) ) );
return 0;
}

/**
* Destroy admin queue
* Disable admin queue
*
* @v intelxl Intel device
* @v admin Admin queue
*/
static void intelxl_destroy_admin ( struct intelxl_nic *intelxl,
static void intelxl_disable_admin ( struct intelxl_nic *intelxl,
struct intelxl_admin *admin ) {
size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC );
size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
const struct intelxl_admin_offsets *regs = admin->regs;
void *admin_regs = ( intelxl->regs + admin->base );

/* Disable queue */
writel ( 0, admin_regs + regs->len );
}

/**
* Free admin queue
*
* @v intelxl Intel device
* @v admin Admin queue
*/
static void intelxl_free_admin ( struct intelxl_nic *intelxl __unused,
struct intelxl_admin *admin ) {
size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC );
size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );

/* Free queue */
free_dma ( admin->buf, ( buf_len + len ) );
Expand Down Expand Up @@ -705,23 +728,18 @@ static void intelxl_poll_admin ( struct net_device *netdev ) {
* @ret rc Return status code
*/
static int intelxl_open_admin ( struct intelxl_nic *intelxl ) {
unsigned int i;
int rc;

/* Create admin event queue */
if ( ( rc = intelxl_create_admin ( intelxl, &intelxl->event ) ) != 0 )
goto err_create_event;
/* Allocate admin event queue */
if ( ( rc = intelxl_alloc_admin ( intelxl, &intelxl->event ) ) != 0 )
goto err_alloc_event;

/* Create admin command queue */
if ( ( rc = intelxl_create_admin ( intelxl, &intelxl->command ) ) != 0 )
goto err_create_command;

/* Initialise all admin event queue descriptors */
for ( i = 0 ; i < INTELXL_ADMIN_NUM_DESC ; i++ )
intelxl_admin_event_init ( intelxl, i );
/* Allocate admin command queue */
if ( ( rc = intelxl_alloc_admin ( intelxl, &intelxl->command ) ) != 0 )
goto err_alloc_command;

/* Post all descriptors to event queue */
intelxl_refill_admin ( intelxl );
/* (Re)open admin queues */
intelxl_reopen_admin ( intelxl );

/* Get firmware version */
if ( ( rc = intelxl_admin_version ( intelxl ) ) != 0 )
Expand All @@ -735,13 +753,37 @@ static int intelxl_open_admin ( struct intelxl_nic *intelxl ) {

err_driver:
err_version:
intelxl_destroy_admin ( intelxl, &intelxl->command );
err_create_command:
intelxl_destroy_admin ( intelxl, &intelxl->event );
err_create_event:
intelxl_disable_admin ( intelxl, &intelxl->command );
intelxl_disable_admin ( intelxl, &intelxl->event );
intelxl_free_admin ( intelxl, &intelxl->command );
err_alloc_command:
intelxl_free_admin ( intelxl, &intelxl->event );
err_alloc_event:
return rc;
}

/**
* Reopen admin queues (after virtual function reset)
*
* @v intelxl Intel device
*/
static void intelxl_reopen_admin ( struct intelxl_nic *intelxl ) {
unsigned int i;

/* Enable admin event queue */
intelxl_enable_admin ( intelxl, &intelxl->event );

/* Enable admin command queue */
intelxl_enable_admin ( intelxl, &intelxl->command );

/* Initialise all admin event queue descriptors */
for ( i = 0 ; i < INTELXL_ADMIN_NUM_DESC ; i++ )
intelxl_admin_event_init ( intelxl, i );

/* Post all descriptors to event queue */
intelxl_refill_admin ( intelxl );
}

/**
* Close admin queues
*
Expand All @@ -752,11 +794,13 @@ static void intelxl_close_admin ( struct intelxl_nic *intelxl ) {
/* Shut down admin queues */
intelxl_admin_shutdown ( intelxl );

/* Destroy admin command queue */
intelxl_destroy_admin ( intelxl, &intelxl->command );
/* Disable admin queues */
intelxl_disable_admin ( intelxl, &intelxl->command );
intelxl_disable_admin ( intelxl, &intelxl->event );

/* Destroy admin event queue */
intelxl_destroy_admin ( intelxl, &intelxl->event );
/* Free admin queues */
intelxl_free_admin ( intelxl, &intelxl->command );
intelxl_free_admin ( intelxl, &intelxl->event );
}

/******************************************************************************
Expand Down

0 comments on commit 7b68c31

Please sign in to comment.