[intelxl] Use one admin queue buffer per admin queue descriptor

We currently use a single data buffer shared between all admin queue
descriptors.  This works for the physical function driver since we
have at most one command in progress and only a single event (which
does not use a data buffer).

The communication path between the physical and virtual function
drivers uses the event data buffer, and there is no way to prevent a
solicited event (i.e. a response to a request) from being overwritten
by an unsolicited event (e.g. a link status change).

Provide individual data buffers for each admin event queue descriptor
(and for each admin command queue descriptor, for the sake of
consistency).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/92/head
Michael Brown 2019-04-24 12:18:12 +01:00
parent c5ccfe79cf
commit 8f3e648b6c
2 changed files with 197 additions and 118 deletions

View File

@ -141,17 +141,17 @@ static const struct intelxl_admin_offsets intelxl_admin_offsets = {
*/ */
static int intelxl_create_admin ( struct intelxl_nic *intelxl, static int intelxl_create_admin ( struct intelxl_nic *intelxl,
struct intelxl_admin *admin ) { 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 ); size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
const struct intelxl_admin_offsets *regs = admin->regs; const struct intelxl_admin_offsets *regs = admin->regs;
void *admin_regs = ( intelxl->regs + admin->base ); void *admin_regs = ( intelxl->regs + admin->base );
physaddr_t address; physaddr_t address;
/* Allocate admin queue */ /* Allocate admin queue */
admin->desc = malloc_dma ( ( len + sizeof ( *admin->buffer ) ), admin->buf = malloc_dma ( ( buf_len + len ), INTELXL_ALIGN );
INTELXL_ALIGN ); if ( ! admin->buf )
if ( ! admin->desc )
return -ENOMEM; return -ENOMEM;
admin->buffer = ( ( ( void * ) admin->desc ) + len ); admin->desc = ( ( ( void * ) admin->buf ) + buf_len );
/* Initialise admin queue */ /* Initialise admin queue */
memset ( admin->desc, 0, len ); memset ( admin->desc, 0, len );
@ -183,9 +183,9 @@ static int intelxl_create_admin ( struct intelxl_nic *intelxl,
( ( admin == &intelxl->command ) ? 'T' : 'R' ), ( ( admin == &intelxl->command ) ? 'T' : 'R' ),
( ( unsigned long long ) address ), ( ( unsigned long long ) address ),
( ( unsigned long long ) address + len ), ( ( unsigned long long ) address + len ),
( ( unsigned long long ) virt_to_bus ( admin->buffer ) ), ( ( unsigned long long ) virt_to_bus ( admin->buf ) ),
( ( unsigned long long ) ( virt_to_bus ( admin->buffer ) + ( ( unsigned long long ) ( virt_to_bus ( admin->buf ) +
sizeof ( admin->buffer[0] ) ) ) ); buf_len ) ) );
return 0; return 0;
} }
@ -197,6 +197,7 @@ static int intelxl_create_admin ( struct intelxl_nic *intelxl,
*/ */
static void intelxl_destroy_admin ( struct intelxl_nic *intelxl, static void intelxl_destroy_admin ( struct intelxl_nic *intelxl,
struct intelxl_admin *admin ) { 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 ); size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
const struct intelxl_admin_offsets *regs = admin->regs; const struct intelxl_admin_offsets *regs = admin->regs;
void *admin_regs = ( intelxl->regs + admin->base ); void *admin_regs = ( intelxl->regs + admin->base );
@ -205,23 +206,80 @@ static void intelxl_destroy_admin ( struct intelxl_nic *intelxl,
writel ( 0, admin_regs + regs->len ); writel ( 0, admin_regs + regs->len );
/* Free queue */ /* Free queue */
free_dma ( admin->desc, ( len + sizeof ( *admin->buffer ) ) ); free_dma ( admin->buf, ( buf_len + len ) );
}
/**
* Get next admin command queue descriptor
*
* @v intelxl Intel device
* @ret cmd Command descriptor
*/
static struct intelxl_admin_descriptor *
intelxl_admin_command_descriptor ( struct intelxl_nic *intelxl ) {
struct intelxl_admin *admin = &intelxl->command;
struct intelxl_admin_descriptor *cmd;
/* Get and initialise next descriptor */
cmd = &admin->desc[ admin->index % INTELXL_ADMIN_NUM_DESC ];
memset ( cmd, 0, sizeof ( *cmd ) );
return cmd;
}
/**
* Get next admin command queue data buffer
*
* @v intelxl Intel device
* @ret buf Data buffer
*/
static union intelxl_admin_buffer *
intelxl_admin_command_buffer ( struct intelxl_nic *intelxl ) {
struct intelxl_admin *admin = &intelxl->command;
union intelxl_admin_buffer *buf;
/* Get next data buffer */
buf = &admin->buf[ admin->index % INTELXL_ADMIN_NUM_DESC ];
memset ( buf, 0, sizeof ( *buf ) );
return buf;
}
/**
* Initialise admin event queue descriptor
*
* @v intelxl Intel device
* @v index Event queue index
*/
static void intelxl_admin_event_init ( struct intelxl_nic *intelxl,
unsigned int index ) {
struct intelxl_admin *admin = &intelxl->event;
struct intelxl_admin_descriptor *evt;
union intelxl_admin_buffer *buf;
uint64_t address;
/* Initialise descriptor */
evt = &admin->desc[ index % INTELXL_ADMIN_NUM_DESC ];
buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ];
address = virt_to_bus ( buf );
evt->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
evt->len = cpu_to_le16 ( sizeof ( *buf ) );
evt->params.buffer.high = cpu_to_le32 ( address >> 32 );
evt->params.buffer.low = cpu_to_le32 ( address & 0xffffffffUL );
} }
/** /**
* Issue admin queue command * Issue admin queue command
* *
* @v intelxl Intel device * @v intelxl Intel device
* @v cmd Command descriptor
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_admin_command ( struct intelxl_nic *intelxl, static int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor *cmd ) {
struct intelxl_admin *admin = &intelxl->command; struct intelxl_admin *admin = &intelxl->command;
const struct intelxl_admin_offsets *regs = admin->regs; const struct intelxl_admin_offsets *regs = admin->regs;
void *admin_regs = ( intelxl->regs + admin->base ); void *admin_regs = ( intelxl->regs + admin->base );
struct intelxl_admin_descriptor *desc; struct intelxl_admin_descriptor *cmd;
uint64_t buffer; union intelxl_admin_buffer *buf;
uint64_t address;
uint32_t cookie;
unsigned int index; unsigned int index;
unsigned int tail; unsigned int tail;
unsigned int i; unsigned int i;
@ -230,32 +288,36 @@ static int intelxl_admin_command ( struct intelxl_nic *intelxl,
/* Get next queue entry */ /* Get next queue entry */
index = admin->index++; index = admin->index++;
tail = ( admin->index % INTELXL_ADMIN_NUM_DESC ); tail = ( admin->index % INTELXL_ADMIN_NUM_DESC );
desc = &admin->desc[index % INTELXL_ADMIN_NUM_DESC]; cmd = &admin->desc[ index % INTELXL_ADMIN_NUM_DESC ];
buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ];
DBGC2 ( intelxl, "INTELXL %p admin command %#x opcode %#04x:\n",
intelxl, index, le16_to_cpu ( cmd->opcode ) );
/* Clear must-be-zero flags */ /* Sanity checks */
cmd->flags &= ~cpu_to_le16 ( INTELXL_ADMIN_FL_DD | assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_DD ) ) );
INTELXL_ADMIN_FL_CMP | assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_CMP ) ) );
INTELXL_ADMIN_FL_ERR ); assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_ERR ) ) );
assert ( cmd->ret == 0 );
/* Clear return value */ /* Populate data buffer address if applicable */
cmd->ret = 0; if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
address = virt_to_bus ( buf );
cmd->params.buffer.high = cpu_to_le32 ( address >> 32 );
cmd->params.buffer.low = cpu_to_le32 ( address & 0xffffffffUL );
}
/* Populate cookie */ /* Populate cookie */
cmd->cookie = cpu_to_le32 ( index ); cmd->cookie = cpu_to_le32 ( index );
/* Populate data buffer address if applicable */ /* Record cookie */
if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) { cookie = cmd->cookie;
buffer = virt_to_bus ( admin->buffer );
cmd->params.buffer.high = cpu_to_le32 ( buffer >> 32 );
cmd->params.buffer.low = cpu_to_le32 ( buffer & 0xffffffffUL );
}
/* Copy command descriptor to queue entry */
memcpy ( desc, cmd, sizeof ( *desc ) );
DBGC2 ( intelxl, "INTELXL %p admin command %#x:\n", intelxl, index );
DBGC2_HDA ( intelxl, virt_to_phys ( desc ), desc, sizeof ( *desc ) );
/* Post command descriptor */ /* Post command descriptor */
DBGC2_HDA ( intelxl, virt_to_phys ( cmd ), cmd, sizeof ( *cmd ) );
if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
DBGC2_HDA ( intelxl, virt_to_phys ( buf ), buf,
le16_to_cpu ( cmd->len ) );
}
wmb(); wmb();
writel ( tail, admin_regs + regs->tail ); writel ( tail, admin_regs + regs->tail );
@ -263,36 +325,33 @@ static int intelxl_admin_command ( struct intelxl_nic *intelxl,
for ( i = 0 ; i < INTELXL_ADMIN_MAX_WAIT_MS ; i++ ) { for ( i = 0 ; i < INTELXL_ADMIN_MAX_WAIT_MS ; i++ ) {
/* If response is not complete, delay 1ms and retry */ /* If response is not complete, delay 1ms and retry */
if ( ! ( desc->flags & INTELXL_ADMIN_FL_DD ) ) { if ( ! ( cmd->flags & INTELXL_ADMIN_FL_DD ) ) {
mdelay ( 1 ); mdelay ( 1 );
continue; continue;
} }
DBGC2 ( intelxl, "INTELXL %p admin command %#x response:\n", DBGC2 ( intelxl, "INTELXL %p admin command %#x response:\n",
intelxl, index ); intelxl, index );
DBGC2_HDA ( intelxl, virt_to_phys ( desc ), desc, DBGC2_HDA ( intelxl, virt_to_phys ( cmd ), cmd,
sizeof ( *desc ) ); sizeof ( *cmd ) );
/* Check for cookie mismatch */ /* Check for cookie mismatch */
if ( desc->cookie != cmd->cookie ) { if ( cmd->cookie != cookie ) {
DBGC ( intelxl, "INTELXL %p admin command %#x bad " DBGC ( intelxl, "INTELXL %p admin command %#x bad "
"cookie %#x\n", intelxl, index, "cookie %#x\n", intelxl, index,
le32_to_cpu ( desc->cookie ) ); le32_to_cpu ( cmd->cookie ) );
rc = -EPROTO; rc = -EPROTO;
goto err; goto err;
} }
/* Check for errors */ /* Check for errors */
if ( desc->ret != 0 ) { if ( cmd->ret != 0 ) {
DBGC ( intelxl, "INTELXL %p admin command %#x error " DBGC ( intelxl, "INTELXL %p admin command %#x error "
"%d\n", intelxl, index, "%d\n", intelxl, index,
le16_to_cpu ( desc->ret ) ); le16_to_cpu ( cmd->ret ) );
rc = -EIO; rc = -EIO;
goto err; goto err;
} }
/* Copy response back to command descriptor */
memcpy ( cmd, desc, sizeof ( *cmd ) );
/* Success */ /* Success */
return 0; return 0;
} }
@ -301,8 +360,7 @@ static int intelxl_admin_command ( struct intelxl_nic *intelxl,
DBGC ( intelxl, "INTELXL %p timed out waiting for admin command %#x:\n", DBGC ( intelxl, "INTELXL %p timed out waiting for admin command %#x:\n",
intelxl, index ); intelxl, index );
err: err:
DBGC_HDA ( intelxl, virt_to_phys ( desc ), cmd, sizeof ( *cmd ) ); DBGC_HDA ( intelxl, virt_to_phys ( cmd ), cmd, sizeof ( *cmd ) );
DBGC_HDA ( intelxl, virt_to_phys ( desc ), desc, sizeof ( *desc ) );
return rc; return rc;
} }
@ -313,17 +371,18 @@ static int intelxl_admin_command ( struct intelxl_nic *intelxl,
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_admin_version ( struct intelxl_nic *intelxl ) { static int intelxl_admin_version ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor cmd; struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_version_params *version = &cmd.params.version; struct intelxl_admin_version_params *version;
unsigned int api; unsigned int api;
int rc; int rc;
/* Populate descriptor */ /* Populate descriptor */
memset ( &cmd, 0, sizeof ( cmd ) ); cmd = intelxl_admin_command_descriptor ( intelxl );
cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_VERSION ); cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_VERSION );
version = &cmd->params.version;
/* Issue command */ /* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 ) if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc; return rc;
api = le16_to_cpu ( version->api.major ); api = le16_to_cpu ( version->api.major );
DBGC ( intelxl, "INTELXL %p firmware v%d.%d API v%d.%d\n", DBGC ( intelxl, "INTELXL %p firmware v%d.%d API v%d.%d\n",
@ -348,24 +407,25 @@ static int intelxl_admin_version ( struct intelxl_nic *intelxl ) {
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_admin_driver ( struct intelxl_nic *intelxl ) { static int intelxl_admin_driver ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor cmd; struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_driver_params *driver = &cmd.params.driver; struct intelxl_admin_driver_params *driver;
struct intelxl_admin_driver_buffer *buf = union intelxl_admin_buffer *buf;
&intelxl->command.buffer->driver;
int rc; int rc;
/* Populate descriptor */ /* Populate descriptor */
memset ( &cmd, 0, sizeof ( cmd ) ); cmd = intelxl_admin_command_descriptor ( intelxl );
cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_DRIVER ); cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_DRIVER );
cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF ); cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
cmd.len = cpu_to_le16 ( sizeof ( *buf ) ); cmd->len = cpu_to_le16 ( sizeof ( buf->driver ) );
driver = &cmd->params.driver;
driver->major = product_major_version; driver->major = product_major_version;
driver->minor = product_minor_version; driver->minor = product_minor_version;
snprintf ( buf->name, sizeof ( buf->name ), "%s", buf = intelxl_admin_command_buffer ( intelxl );
snprintf ( buf->driver.name, sizeof ( buf->driver.name ), "%s",
( product_name[0] ? product_name : product_short_name ) ); ( product_name[0] ? product_name : product_short_name ) );
/* Issue command */ /* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 ) if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc; return rc;
return 0; return 0;
@ -378,17 +438,18 @@ static int intelxl_admin_driver ( struct intelxl_nic *intelxl ) {
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_admin_shutdown ( struct intelxl_nic *intelxl ) { static int intelxl_admin_shutdown ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor cmd; struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_shutdown_params *shutdown = &cmd.params.shutdown; struct intelxl_admin_shutdown_params *shutdown;
int rc; int rc;
/* Populate descriptor */ /* Populate descriptor */
memset ( &cmd, 0, sizeof ( cmd ) ); cmd = intelxl_admin_command_descriptor ( intelxl );
cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_SHUTDOWN ); cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SHUTDOWN );
shutdown = &cmd->params.shutdown;
shutdown->unloading = INTELXL_ADMIN_SHUTDOWN_UNLOADING; shutdown->unloading = INTELXL_ADMIN_SHUTDOWN_UNLOADING;
/* Issue command */ /* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 ) if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc; return rc;
return 0; return 0;
@ -401,36 +462,38 @@ static int intelxl_admin_shutdown ( struct intelxl_nic *intelxl ) {
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_admin_switch ( struct intelxl_nic *intelxl ) { static int intelxl_admin_switch ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor cmd; struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_switch_params *sw = &cmd.params.sw; struct intelxl_admin_switch_params *sw;
struct intelxl_admin_switch_buffer *buf = &intelxl->command.buffer->sw; union intelxl_admin_buffer *buf;
struct intelxl_admin_switch_config *cfg = &buf->cfg;
int rc; int rc;
/* Populate descriptor */ /* Populate descriptor */
memset ( &cmd, 0, sizeof ( cmd ) ); cmd = intelxl_admin_command_descriptor ( intelxl );
cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_SWITCH ); cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SWITCH );
cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ); cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
cmd.len = cpu_to_le16 ( sizeof ( *buf ) ); cmd->len = cpu_to_le16 ( sizeof ( buf->sw ) );
sw = &cmd->params.sw;
buf = intelxl_admin_command_buffer ( intelxl );
/* Get each configuration in turn */ /* Get each configuration in turn */
do { do {
/* Issue command */ /* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 ) if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc; return rc;
/* Dump raw configuration */ /* Dump raw configuration */
DBGC2 ( intelxl, "INTELXL %p SEID %#04x:\n", DBGC2 ( intelxl, "INTELXL %p SEID %#04x:\n",
intelxl, le16_to_cpu ( cfg->seid ) ); intelxl, le16_to_cpu ( buf->sw.cfg.seid ) );
DBGC2_HDA ( intelxl, 0, cfg, sizeof ( *cfg ) ); DBGC2_HDA ( intelxl, 0, &buf->sw.cfg, sizeof ( buf->sw.cfg ) );
/* Parse response */ /* Parse response */
if ( cfg->type == INTELXL_ADMIN_SWITCH_TYPE_VSI ) { if ( buf->sw.cfg.type == INTELXL_ADMIN_SWITCH_TYPE_VSI ) {
intelxl->vsi = le16_to_cpu ( cfg->seid ); intelxl->vsi = le16_to_cpu ( buf->sw.cfg.seid );
DBGC ( intelxl, "INTELXL %p VSI %#04x uplink %#04x " DBGC ( intelxl, "INTELXL %p VSI %#04x uplink %#04x "
"downlink %#04x conn %#02x\n", intelxl, "downlink %#04x conn %#02x\n", intelxl,
intelxl->vsi, le16_to_cpu ( cfg->uplink ), intelxl->vsi, le16_to_cpu ( buf->sw.cfg.uplink ),
le16_to_cpu ( cfg->downlink ), cfg->connection ); le16_to_cpu ( buf->sw.cfg.downlink ),
buf->sw.cfg.connection );
} }
} while ( sw->next ); } while ( sw->next );
@ -451,25 +514,27 @@ static int intelxl_admin_switch ( struct intelxl_nic *intelxl ) {
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_admin_vsi ( struct intelxl_nic *intelxl ) { static int intelxl_admin_vsi ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor cmd; struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_vsi_params *vsi = &cmd.params.vsi; struct intelxl_admin_vsi_params *vsi;
struct intelxl_admin_vsi_buffer *buf = &intelxl->command.buffer->vsi; union intelxl_admin_buffer *buf;
int rc; int rc;
/* Populate descriptor */ /* Populate descriptor */
memset ( &cmd, 0, sizeof ( cmd ) ); cmd = intelxl_admin_command_descriptor ( intelxl );
cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_VSI ); cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_VSI );
cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ); cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
cmd.len = cpu_to_le16 ( sizeof ( *buf ) ); cmd->len = cpu_to_le16 ( sizeof ( buf->vsi ) );
vsi = &cmd->params.vsi;
vsi->vsi = cpu_to_le16 ( intelxl->vsi ); vsi->vsi = cpu_to_le16 ( intelxl->vsi );
buf = intelxl_admin_command_buffer ( intelxl );
/* Issue command */ /* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 ) if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc; return rc;
/* Parse response */ /* Parse response */
intelxl->queue = le16_to_cpu ( buf->queue[0] ); intelxl->queue = le16_to_cpu ( buf->vsi.queue[0] );
intelxl->qset = le16_to_cpu ( buf->qset[0] ); intelxl->qset = le16_to_cpu ( buf->vsi.qset[0] );
DBGC ( intelxl, "INTELXL %p VSI %#04x queue %#04x qset %#04x\n", DBGC ( intelxl, "INTELXL %p VSI %#04x queue %#04x qset %#04x\n",
intelxl, intelxl->vsi, intelxl->queue, intelxl->qset ); intelxl, intelxl->vsi, intelxl->queue, intelxl->qset );
@ -483,24 +548,25 @@ static int intelxl_admin_vsi ( struct intelxl_nic *intelxl ) {
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_admin_promisc ( struct intelxl_nic *intelxl ) { static int intelxl_admin_promisc ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor cmd; struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_promisc_params *promisc = &cmd.params.promisc; struct intelxl_admin_promisc_params *promisc;
uint16_t flags; uint16_t flags;
int rc; int rc;
/* Populate descriptor */ /* Populate descriptor */
memset ( &cmd, 0, sizeof ( cmd ) ); cmd = intelxl_admin_command_descriptor ( intelxl );
cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_PROMISC ); cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_PROMISC );
flags = ( INTELXL_ADMIN_PROMISC_FL_UNICAST | flags = ( INTELXL_ADMIN_PROMISC_FL_UNICAST |
INTELXL_ADMIN_PROMISC_FL_MULTICAST | INTELXL_ADMIN_PROMISC_FL_MULTICAST |
INTELXL_ADMIN_PROMISC_FL_BROADCAST | INTELXL_ADMIN_PROMISC_FL_BROADCAST |
INTELXL_ADMIN_PROMISC_FL_VLAN ); INTELXL_ADMIN_PROMISC_FL_VLAN );
promisc = &cmd->params.promisc;
promisc->flags = cpu_to_le16 ( flags ); promisc->flags = cpu_to_le16 ( flags );
promisc->valid = cpu_to_le16 ( flags ); promisc->valid = cpu_to_le16 ( flags );
promisc->vsi = cpu_to_le16 ( intelxl->vsi ); promisc->vsi = cpu_to_le16 ( intelxl->vsi );
/* Issue command */ /* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 ) if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc; return rc;
return 0; return 0;
@ -513,18 +579,19 @@ static int intelxl_admin_promisc ( struct intelxl_nic *intelxl ) {
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_admin_autoneg ( struct intelxl_nic *intelxl ) { static int intelxl_admin_autoneg ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor cmd; struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_autoneg_params *autoneg = &cmd.params.autoneg; struct intelxl_admin_autoneg_params *autoneg;
int rc; int rc;
/* Populate descriptor */ /* Populate descriptor */
memset ( &cmd, 0, sizeof ( cmd ) ); cmd = intelxl_admin_command_descriptor ( intelxl );
cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_AUTONEG ); cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_AUTONEG );
autoneg = &cmd->params.autoneg;
autoneg->flags = ( INTELXL_ADMIN_AUTONEG_FL_RESTART | autoneg->flags = ( INTELXL_ADMIN_AUTONEG_FL_RESTART |
INTELXL_ADMIN_AUTONEG_FL_ENABLE ); INTELXL_ADMIN_AUTONEG_FL_ENABLE );
/* Issue command */ /* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 ) if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc; return rc;
return 0; return 0;
@ -538,17 +605,18 @@ static int intelxl_admin_autoneg ( struct intelxl_nic *intelxl ) {
*/ */
static int intelxl_admin_link ( struct net_device *netdev ) { static int intelxl_admin_link ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv; struct intelxl_nic *intelxl = netdev->priv;
struct intelxl_admin_descriptor cmd; struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_link_params *link = &cmd.params.link; struct intelxl_admin_link_params *link;
int rc; int rc;
/* Populate descriptor */ /* Populate descriptor */
memset ( &cmd, 0, sizeof ( cmd ) ); cmd = intelxl_admin_command_descriptor ( intelxl );
cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_LINK ); cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_LINK );
link = &cmd->params.link;
link->notify = INTELXL_ADMIN_LINK_NOTIFY; link->notify = INTELXL_ADMIN_LINK_NOTIFY;
/* Issue command */ /* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 ) if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc; return rc;
DBGC ( intelxl, "INTELXL %p PHY %#02x speed %#02x status %#02x\n", DBGC ( intelxl, "INTELXL %p PHY %#02x speed %#02x status %#02x\n",
intelxl, link->phy, link->speed, link->status ); intelxl, link->phy, link->speed, link->status );
@ -577,6 +645,7 @@ static void intelxl_refill_admin ( struct intelxl_nic *intelxl ) {
/* Update tail pointer */ /* Update tail pointer */
tail = ( ( admin->index + INTELXL_ADMIN_NUM_DESC - 1 ) % tail = ( ( admin->index + INTELXL_ADMIN_NUM_DESC - 1 ) %
INTELXL_ADMIN_NUM_DESC ); INTELXL_ADMIN_NUM_DESC );
wmb();
writel ( tail, admin_regs + regs->tail ); writel ( tail, admin_regs + regs->tail );
} }
@ -588,39 +657,42 @@ static void intelxl_refill_admin ( struct intelxl_nic *intelxl ) {
static void intelxl_poll_admin ( struct net_device *netdev ) { static void intelxl_poll_admin ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv; struct intelxl_nic *intelxl = netdev->priv;
struct intelxl_admin *admin = &intelxl->event; struct intelxl_admin *admin = &intelxl->event;
struct intelxl_admin_descriptor *desc; struct intelxl_admin_descriptor *evt;
union intelxl_admin_buffer *buf;
/* Check for events */ /* Check for events */
while ( 1 ) { while ( 1 ) {
/* Get next event descriptor */ /* Get next event descriptor and data buffer */
desc = &admin->desc[admin->index % INTELXL_ADMIN_NUM_DESC]; evt = &admin->desc[ admin->index % INTELXL_ADMIN_NUM_DESC ];
buf = &admin->buf[ admin->index % INTELXL_ADMIN_NUM_DESC ];
/* Stop if descriptor is not yet completed */ /* Stop if descriptor is not yet completed */
if ( ! ( desc->flags & INTELXL_ADMIN_FL_DD ) ) if ( ! ( evt->flags & INTELXL_ADMIN_FL_DD ) )
return; return;
DBGC2 ( intelxl, "INTELXL %p admin event %#x:\n", DBGC2 ( intelxl, "INTELXL %p admin event %#x:\n",
intelxl, admin->index ); intelxl, admin->index );
DBGC2_HDA ( intelxl, virt_to_phys ( desc ), desc, DBGC2_HDA ( intelxl, virt_to_phys ( evt ), evt,
sizeof ( *desc ) ); sizeof ( *evt ) );
if ( evt->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
DBGC2_HDA ( intelxl, virt_to_phys ( buf ), buf,
le16_to_cpu ( evt->len ) );
}
/* Handle event */ /* Handle event */
switch ( desc->opcode ) { switch ( evt->opcode ) {
case cpu_to_le16 ( INTELXL_ADMIN_LINK ): case cpu_to_le16 ( INTELXL_ADMIN_LINK ):
intelxl_admin_link ( netdev ); intelxl_admin_link ( netdev );
break; break;
default: default:
DBGC ( intelxl, "INTELXL %p admin event %#x " DBGC ( intelxl, "INTELXL %p admin event %#x "
"unrecognised opcode %#04x\n", intelxl, "unrecognised opcode %#04x\n", intelxl,
admin->index, le16_to_cpu ( desc->opcode ) ); admin->index, le16_to_cpu ( evt->opcode ) );
break; break;
} }
/* Clear event completion flag */ /* Reset descriptor and refill queue */
desc->flags = 0; intelxl_admin_event_init ( intelxl, admin->index );
wmb();
/* Update index and refill queue */
admin->index++; admin->index++;
intelxl_refill_admin ( intelxl ); intelxl_refill_admin ( intelxl );
} }
@ -633,6 +705,7 @@ static void intelxl_poll_admin ( struct net_device *netdev ) {
* @ret rc Return status code * @ret rc Return status code
*/ */
static int intelxl_open_admin ( struct intelxl_nic *intelxl ) { static int intelxl_open_admin ( struct intelxl_nic *intelxl ) {
unsigned int i;
int rc; int rc;
/* Create admin event queue */ /* Create admin event queue */
@ -643,6 +716,10 @@ static int intelxl_open_admin ( struct intelxl_nic *intelxl ) {
if ( ( rc = intelxl_create_admin ( intelxl, &intelxl->command ) ) != 0 ) if ( ( rc = intelxl_create_admin ( intelxl, &intelxl->command ) ) != 0 )
goto err_create_command; 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 );
/* Post all descriptors to event queue */ /* Post all descriptors to event queue */
intelxl_refill_admin ( intelxl ); intelxl_refill_admin ( intelxl );

View File

@ -319,6 +319,8 @@ union intelxl_admin_buffer {
struct intelxl_admin_switch_buffer sw; struct intelxl_admin_switch_buffer sw;
/** Get VSI Parameters data buffer */ /** Get VSI Parameters data buffer */
struct intelxl_admin_vsi_buffer vsi; struct intelxl_admin_vsi_buffer vsi;
/** Alignment padding */
uint8_t pad[INTELXL_ALIGN];
} __attribute__ (( packed )); } __attribute__ (( packed ));
/** Admin queue descriptor */ /** Admin queue descriptor */
@ -358,6 +360,8 @@ struct intelxl_admin_descriptor {
struct intelxl_admin { struct intelxl_admin {
/** Descriptors */ /** Descriptors */
struct intelxl_admin_descriptor *desc; struct intelxl_admin_descriptor *desc;
/** Data buffers */
union intelxl_admin_buffer *buf;
/** Queue index */ /** Queue index */
unsigned int index; unsigned int index;
@ -365,8 +369,6 @@ struct intelxl_admin {
unsigned int base; unsigned int base;
/** Register offsets */ /** Register offsets */
const struct intelxl_admin_offsets *regs; const struct intelxl_admin_offsets *regs;
/** Data buffer */
union intelxl_admin_buffer *buffer;
}; };
/** /**