]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[intelxl] Use one admin queue buffer per admin queue descriptor
authorMichael Brown <mcb30@ipxe.org>
Wed, 24 Apr 2019 11:18:12 +0000 (12:18 +0100)
committerMichael Brown <mcb30@ipxe.org>
Sat, 27 Apr 2019 19:25:59 +0000 (20:25 +0100)
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>
src/drivers/net/intelxl.c
src/drivers/net/intelxl.h

index 1f0ca2c086fd3ae615bef3d22257fba21ca28a62..c0fb4c24ec2f93704c08d67a88daacd370aedb43 100644 (file)
@@ -141,17 +141,17 @@ static const struct intelxl_admin_offsets intelxl_admin_offsets = {
  */
 static int intelxl_create_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->desc = malloc_dma ( ( len + sizeof ( *admin->buffer ) ),
-                                  INTELXL_ALIGN );
-       if ( ! admin->desc )
+       admin->buf = malloc_dma ( ( buf_len + len ), INTELXL_ALIGN );
+       if ( ! admin->buf )
                return -ENOMEM;
-       admin->buffer = ( ( ( void * ) admin->desc ) + len );
+       admin->desc = ( ( ( void * ) admin->buf ) + buf_len );
 
        /* Initialise admin queue */
        memset ( admin->desc, 0, len );
@@ -183,9 +183,9 @@ static int intelxl_create_admin ( struct intelxl_nic *intelxl,
               ( ( admin == &intelxl->command ) ? 'T' : 'R' ),
               ( ( unsigned long long ) address ),
               ( ( unsigned long long ) address + len ),
-              ( ( unsigned long long ) virt_to_bus ( admin->buffer ) ),
-              ( ( unsigned long long ) ( virt_to_bus ( admin->buffer ) +
-                                         sizeof ( admin->buffer[0] ) ) ) );
+              ( ( unsigned long long ) virt_to_bus ( admin->buf ) ),
+              ( ( unsigned long long ) ( virt_to_bus ( admin->buf ) +
+                                         buf_len ) ) );
        return 0;
 }
 
@@ -197,6 +197,7 @@ static int intelxl_create_admin ( struct intelxl_nic *intelxl,
  */
 static void intelxl_destroy_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 );
@@ -205,23 +206,80 @@ static void intelxl_destroy_admin ( struct intelxl_nic *intelxl,
        writel ( 0, admin_regs + regs->len );
 
        /* 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
  *
  * @v intelxl          Intel device
- * @v cmd              Command descriptor
  * @ret rc             Return status code
  */
-static int intelxl_admin_command ( struct intelxl_nic *intelxl,
-                                  struct intelxl_admin_descriptor *cmd ) {
+static int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
        struct intelxl_admin *admin = &intelxl->command;
        const struct intelxl_admin_offsets *regs = admin->regs;
        void *admin_regs = ( intelxl->regs + admin->base );
-       struct intelxl_admin_descriptor *desc;
-       uint64_t buffer;
+       struct intelxl_admin_descriptor *cmd;
+       union intelxl_admin_buffer *buf;
+       uint64_t address;
+       uint32_t cookie;
        unsigned int index;
        unsigned int tail;
        unsigned int i;
@@ -230,32 +288,36 @@ static int intelxl_admin_command ( struct intelxl_nic *intelxl,
        /* Get next queue entry */
        index = admin->index++;
        tail = ( admin->index % INTELXL_ADMIN_NUM_DESC );
-       desc = &admin->desc[index % INTELXL_ADMIN_NUM_DESC];
-
-       /* Clear must-be-zero flags */
-       cmd->flags &= ~cpu_to_le16 ( INTELXL_ADMIN_FL_DD |
-                                    INTELXL_ADMIN_FL_CMP |
-                                    INTELXL_ADMIN_FL_ERR );
-
-       /* Clear return value */
-       cmd->ret = 0;
+       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 ) );
 
-       /* Populate cookie */
-       cmd->cookie = cpu_to_le32 ( index );
+       /* Sanity checks */
+       assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_DD ) ) );
+       assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_CMP ) ) );
+       assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_ERR ) ) );
+       assert ( cmd->ret == 0 );
 
        /* Populate data buffer address if applicable */
        if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
-               buffer = virt_to_bus ( admin->buffer );
-               cmd->params.buffer.high = cpu_to_le32 ( buffer >> 32 );
-               cmd->params.buffer.low = cpu_to_le32 ( buffer & 0xffffffffUL );
+               address = virt_to_bus ( buf );
+               cmd->params.buffer.high = cpu_to_le32 ( address >> 32 );
+               cmd->params.buffer.low = cpu_to_le32 ( address & 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 ) );
+       /* Populate cookie */
+       cmd->cookie = cpu_to_le32 ( index );
+
+       /* Record cookie */
+       cookie = cmd->cookie;
 
        /* 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();
        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++ ) {
 
                /* 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 );
                        continue;
                }
                DBGC2 ( intelxl, "INTELXL %p admin command %#x response:\n",
                        intelxl, index );
-               DBGC2_HDA ( intelxl, virt_to_phys ( desc ), desc,
-                           sizeof ( *desc ) );
+               DBGC2_HDA ( intelxl, virt_to_phys ( cmd ), cmd,
+                           sizeof ( *cmd ) );
 
                /* Check for cookie mismatch */
-               if ( desc->cookie != cmd->cookie ) {
+               if ( cmd->cookie != cookie ) {
                        DBGC ( intelxl, "INTELXL %p admin command %#x bad "
                               "cookie %#x\n", intelxl, index,
-                              le32_to_cpu ( desc->cookie ) );
+                              le32_to_cpu ( cmd->cookie ) );
                        rc = -EPROTO;
                        goto err;
                }
 
                /* Check for errors */
-               if ( desc->ret != 0 ) {
+               if ( cmd->ret != 0 ) {
                        DBGC ( intelxl, "INTELXL %p admin command %#x error "
                               "%d\n", intelxl, index,
-                              le16_to_cpu ( desc->ret ) );
+                              le16_to_cpu ( cmd->ret ) );
                        rc = -EIO;
                        goto err;
                }
 
-               /* Copy response back to command descriptor */
-               memcpy ( cmd, desc, sizeof ( *cmd ) );
-
                /* Success */
                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",
               intelxl, index );
  err:
-       DBGC_HDA ( intelxl, virt_to_phys ( desc ), cmd, sizeof ( *cmd ) );
-       DBGC_HDA ( intelxl, virt_to_phys ( desc ), desc, sizeof ( *desc ) );
+       DBGC_HDA ( intelxl, virt_to_phys ( cmd ), cmd, sizeof ( *cmd ) );
        return rc;
 }
 
@@ -313,17 +371,18 @@ static int intelxl_admin_command ( struct intelxl_nic *intelxl,
  * @ret rc             Return status code
  */
 static int intelxl_admin_version ( struct intelxl_nic *intelxl ) {
-       struct intelxl_admin_descriptor cmd;
-       struct intelxl_admin_version_params *version = &cmd.params.version;
+       struct intelxl_admin_descriptor *cmd;
+       struct intelxl_admin_version_params *version;
        unsigned int api;
        int rc;
 
        /* Populate descriptor */
-       memset ( &cmd, 0, sizeof ( cmd ) );
-       cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_VERSION );
+       cmd = intelxl_admin_command_descriptor ( intelxl );
+       cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_VERSION );
+       version = &cmd->params.version;
 
        /* Issue command */
-       if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
+       if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
                return rc;
        api = le16_to_cpu ( version->api.major );
        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
  */
 static int intelxl_admin_driver ( struct intelxl_nic *intelxl ) {
-       struct intelxl_admin_descriptor cmd;
-       struct intelxl_admin_driver_params *driver = &cmd.params.driver;
-       struct intelxl_admin_driver_buffer *buf =
-               &intelxl->command.buffer->driver;
+       struct intelxl_admin_descriptor *cmd;
+       struct intelxl_admin_driver_params *driver;
+       union intelxl_admin_buffer *buf;
        int rc;
 
        /* Populate descriptor */
-       memset ( &cmd, 0, sizeof ( cmd ) );
-       cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_DRIVER );
-       cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
-       cmd.len = cpu_to_le16 ( sizeof ( *buf ) );
+       cmd = intelxl_admin_command_descriptor ( intelxl );
+       cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_DRIVER );
+       cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
+       cmd->len = cpu_to_le16 ( sizeof ( buf->driver ) );
+       driver = &cmd->params.driver;
        driver->major = product_major_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 ) );
 
        /* Issue command */
-       if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
+       if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
                return rc;
 
        return 0;
@@ -378,17 +438,18 @@ static int intelxl_admin_driver ( struct intelxl_nic *intelxl ) {
  * @ret rc             Return status code
  */
 static int intelxl_admin_shutdown ( struct intelxl_nic *intelxl ) {
-       struct intelxl_admin_descriptor cmd;
-       struct intelxl_admin_shutdown_params *shutdown = &cmd.params.shutdown;
+       struct intelxl_admin_descriptor *cmd;
+       struct intelxl_admin_shutdown_params *shutdown;
        int rc;
 
        /* Populate descriptor */
-       memset ( &cmd, 0, sizeof ( cmd ) );
-       cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_SHUTDOWN );
+       cmd = intelxl_admin_command_descriptor ( intelxl );
+       cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SHUTDOWN );
+       shutdown = &cmd->params.shutdown;
        shutdown->unloading = INTELXL_ADMIN_SHUTDOWN_UNLOADING;
 
        /* Issue command */
-       if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
+       if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
                return rc;
 
        return 0;
@@ -401,36 +462,38 @@ static int intelxl_admin_shutdown ( struct intelxl_nic *intelxl ) {
  * @ret rc             Return status code
  */
 static int intelxl_admin_switch ( struct intelxl_nic *intelxl ) {
-       struct intelxl_admin_descriptor cmd;
-       struct intelxl_admin_switch_params *sw = &cmd.params.sw;
-       struct intelxl_admin_switch_buffer *buf = &intelxl->command.buffer->sw;
-       struct intelxl_admin_switch_config *cfg = &buf->cfg;
+       struct intelxl_admin_descriptor *cmd;
+       struct intelxl_admin_switch_params *sw;
+       union intelxl_admin_buffer *buf;
        int rc;
 
        /* Populate descriptor */
-       memset ( &cmd, 0, sizeof ( cmd ) );
-       cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_SWITCH );
-       cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
-       cmd.len = cpu_to_le16 ( sizeof ( *buf ) );
+       cmd = intelxl_admin_command_descriptor ( intelxl );
+       cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SWITCH );
+       cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
+       cmd->len = cpu_to_le16 ( sizeof ( buf->sw ) );
+       sw = &cmd->params.sw;
+       buf = intelxl_admin_command_buffer ( intelxl );
 
        /* Get each configuration in turn */
        do {
                /* Issue command */
-               if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
+               if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
                        return rc;
 
                /* Dump raw configuration */
                DBGC2 ( intelxl, "INTELXL %p SEID %#04x:\n",
-                       intelxl, le16_to_cpu ( cfg->seid ) );
-               DBGC2_HDA ( intelxl, 0, cfg, sizeof ( *cfg ) );
+                       intelxl, le16_to_cpu ( buf->sw.cfg.seid ) );
+               DBGC2_HDA ( intelxl, 0, &buf->sw.cfg, sizeof ( buf->sw.cfg ) );
 
                /* Parse response */
-               if ( cfg->type == INTELXL_ADMIN_SWITCH_TYPE_VSI ) {
-                       intelxl->vsi = le16_to_cpu ( cfg->seid );
+               if ( buf->sw.cfg.type == INTELXL_ADMIN_SWITCH_TYPE_VSI ) {
+                       intelxl->vsi = le16_to_cpu ( buf->sw.cfg.seid );
                        DBGC ( intelxl, "INTELXL %p VSI %#04x uplink %#04x "
                               "downlink %#04x conn %#02x\n", intelxl,
-                              intelxl->vsi, le16_to_cpu ( cfg->uplink ),
-                              le16_to_cpu ( cfg->downlink ), cfg->connection );
+                              intelxl->vsi, le16_to_cpu ( buf->sw.cfg.uplink ),
+                              le16_to_cpu ( buf->sw.cfg.downlink ),
+                              buf->sw.cfg.connection );
                }
 
        } while ( sw->next );
@@ -451,25 +514,27 @@ static int intelxl_admin_switch ( struct intelxl_nic *intelxl ) {
  * @ret rc             Return status code
  */
 static int intelxl_admin_vsi ( struct intelxl_nic *intelxl ) {
-       struct intelxl_admin_descriptor cmd;
-       struct intelxl_admin_vsi_params *vsi = &cmd.params.vsi;
-       struct intelxl_admin_vsi_buffer *buf = &intelxl->command.buffer->vsi;
+       struct intelxl_admin_descriptor *cmd;
+       struct intelxl_admin_vsi_params *vsi;
+       union intelxl_admin_buffer *buf;
        int rc;
 
        /* Populate descriptor */
-       memset ( &cmd, 0, sizeof ( cmd ) );
-       cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_VSI );
-       cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
-       cmd.len = cpu_to_le16 ( sizeof ( *buf ) );
+       cmd = intelxl_admin_command_descriptor ( intelxl );
+       cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_VSI );
+       cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
+       cmd->len = cpu_to_le16 ( sizeof ( buf->vsi ) );
+       vsi = &cmd->params.vsi;
        vsi->vsi = cpu_to_le16 ( intelxl->vsi );
+       buf = intelxl_admin_command_buffer ( intelxl );
 
        /* Issue command */
-       if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
+       if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
                return rc;
 
        /* Parse response */
-       intelxl->queue = le16_to_cpu ( buf->queue[0] );
-       intelxl->qset = le16_to_cpu ( buf->qset[0] );
+       intelxl->queue = le16_to_cpu ( buf->vsi.queue[0] );
+       intelxl->qset = le16_to_cpu ( buf->vsi.qset[0] );
        DBGC ( intelxl, "INTELXL %p VSI %#04x queue %#04x qset %#04x\n",
               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
  */
 static int intelxl_admin_promisc ( struct intelxl_nic *intelxl ) {
-       struct intelxl_admin_descriptor cmd;
-       struct intelxl_admin_promisc_params *promisc = &cmd.params.promisc;
+       struct intelxl_admin_descriptor *cmd;
+       struct intelxl_admin_promisc_params *promisc;
        uint16_t flags;
        int rc;
 
        /* Populate descriptor */
-       memset ( &cmd, 0, sizeof ( cmd ) );
-       cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_PROMISC );
+       cmd = intelxl_admin_command_descriptor ( intelxl );
+       cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_PROMISC );
        flags = ( INTELXL_ADMIN_PROMISC_FL_UNICAST |
                  INTELXL_ADMIN_PROMISC_FL_MULTICAST |
                  INTELXL_ADMIN_PROMISC_FL_BROADCAST |
                  INTELXL_ADMIN_PROMISC_FL_VLAN );
+       promisc = &cmd->params.promisc;
        promisc->flags = cpu_to_le16 ( flags );
        promisc->valid = cpu_to_le16 ( flags );
        promisc->vsi = cpu_to_le16 ( intelxl->vsi );
 
        /* Issue command */
-       if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
+       if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
                return rc;
 
        return 0;
@@ -513,18 +579,19 @@ static int intelxl_admin_promisc ( struct intelxl_nic *intelxl ) {
  * @ret rc             Return status code
  */
 static int intelxl_admin_autoneg ( struct intelxl_nic *intelxl ) {
-       struct intelxl_admin_descriptor cmd;
-       struct intelxl_admin_autoneg_params *autoneg = &cmd.params.autoneg;
+       struct intelxl_admin_descriptor *cmd;
+       struct intelxl_admin_autoneg_params *autoneg;
        int rc;
 
        /* Populate descriptor */
-       memset ( &cmd, 0, sizeof ( cmd ) );
-       cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_AUTONEG );
+       cmd = intelxl_admin_command_descriptor ( intelxl );
+       cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_AUTONEG );
+       autoneg = &cmd->params.autoneg;
        autoneg->flags = ( INTELXL_ADMIN_AUTONEG_FL_RESTART |
                           INTELXL_ADMIN_AUTONEG_FL_ENABLE );
 
        /* Issue command */
-       if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
+       if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
                return rc;
 
        return 0;
@@ -538,17 +605,18 @@ static int intelxl_admin_autoneg ( struct intelxl_nic *intelxl ) {
  */
 static int intelxl_admin_link ( struct net_device *netdev ) {
        struct intelxl_nic *intelxl = netdev->priv;
-       struct intelxl_admin_descriptor cmd;
-       struct intelxl_admin_link_params *link = &cmd.params.link;
+       struct intelxl_admin_descriptor *cmd;
+       struct intelxl_admin_link_params *link;
        int rc;
 
        /* Populate descriptor */
-       memset ( &cmd, 0, sizeof ( cmd ) );
-       cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_LINK );
+       cmd = intelxl_admin_command_descriptor ( intelxl );
+       cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_LINK );
+       link = &cmd->params.link;
        link->notify = INTELXL_ADMIN_LINK_NOTIFY;
 
        /* Issue command */
-       if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
+       if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
                return rc;
        DBGC ( intelxl, "INTELXL %p PHY %#02x speed %#02x status %#02x\n",
               intelxl, link->phy, link->speed, link->status );
@@ -577,6 +645,7 @@ static void intelxl_refill_admin ( struct intelxl_nic *intelxl ) {
        /* Update tail pointer */
        tail = ( ( admin->index + INTELXL_ADMIN_NUM_DESC - 1 ) %
                 INTELXL_ADMIN_NUM_DESC );
+       wmb();
        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 ) {
        struct intelxl_nic *intelxl = netdev->priv;
        struct intelxl_admin *admin = &intelxl->event;
-       struct intelxl_admin_descriptor *desc;
+       struct intelxl_admin_descriptor *evt;
+       union intelxl_admin_buffer *buf;
 
        /* Check for events */
        while ( 1 ) {
 
-               /* Get next event descriptor */
-               desc = &admin->desc[admin->index % INTELXL_ADMIN_NUM_DESC];
+               /* Get next event descriptor and data buffer */
+               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 */
-               if ( ! ( desc->flags & INTELXL_ADMIN_FL_DD ) )
+               if ( ! ( evt->flags & INTELXL_ADMIN_FL_DD ) )
                        return;
                DBGC2 ( intelxl, "INTELXL %p admin event %#x:\n",
                        intelxl, admin->index );
-               DBGC2_HDA ( intelxl, virt_to_phys ( desc ), desc,
-                           sizeof ( *desc ) );
+               DBGC2_HDA ( intelxl, virt_to_phys ( evt ), evt,
+                           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 */
-               switch ( desc->opcode ) {
+               switch ( evt->opcode ) {
                case cpu_to_le16 ( INTELXL_ADMIN_LINK ):
                        intelxl_admin_link ( netdev );
                        break;
                default:
                        DBGC ( intelxl, "INTELXL %p admin event %#x "
                               "unrecognised opcode %#04x\n", intelxl,
-                              admin->index, le16_to_cpu ( desc->opcode ) );
+                              admin->index, le16_to_cpu ( evt->opcode ) );
                        break;
                }
 
-               /* Clear event completion flag */
-               desc->flags = 0;
-               wmb();
-
-               /* Update index and refill queue */
+               /* Reset descriptor and refill queue */
+               intelxl_admin_event_init ( intelxl, admin->index );
                admin->index++;
                intelxl_refill_admin ( intelxl );
        }
@@ -633,6 +705,7 @@ 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 */
@@ -643,6 +716,10 @@ static int intelxl_open_admin ( struct intelxl_nic *intelxl ) {
        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 );
+
        /* Post all descriptors to event queue */
        intelxl_refill_admin ( intelxl );
 
index 138fc2ef0974841610ee2357257ef5b882c897dc..0175c1f9d01fada9ecf9470be0f65345bd3c983e 100644 (file)
@@ -319,6 +319,8 @@ union intelxl_admin_buffer {
        struct intelxl_admin_switch_buffer sw;
        /** Get VSI Parameters data buffer */
        struct intelxl_admin_vsi_buffer vsi;
+       /** Alignment padding */
+       uint8_t pad[INTELXL_ALIGN];
 } __attribute__ (( packed ));
 
 /** Admin queue descriptor */
@@ -358,6 +360,8 @@ struct intelxl_admin_descriptor {
 struct intelxl_admin {
        /** Descriptors */
        struct intelxl_admin_descriptor *desc;
+       /** Data buffers */
+       union intelxl_admin_buffer *buf;
        /** Queue index */
        unsigned int index;
 
@@ -365,8 +369,6 @@ struct intelxl_admin {
        unsigned int base;
        /** Register offsets */
        const struct intelxl_admin_offsets *regs;
-       /** Data buffer */
-       union intelxl_admin_buffer *buffer;
 };
 
 /**