net/bnxt: add Rx queue create/destroy
authorAjit Khaparde <ajit.khaparde@broadcom.com>
Wed, 15 Jun 2016 21:23:11 +0000 (14:23 -0700)
committerBruce Richardson <bruce.richardson@intel.com>
Mon, 20 Jun 2016 15:21:51 +0000 (17:21 +0200)
In this patch we are adding the bnxt_rx_queue_setup_op() and
bnxt_rx_queue_release_op() functions. These will be tied to the
rx_queue_setup and rx_queue_release dev_ops in a subsequent patch.
In these functions we allocate/free memory for the RX queues.

This still requires support to create a RX ring in the ASIC which
will be completed in a future commit. Each Rx queue created via the
rx_queue_setup dev_op will have an associated Rx ring in the hardware.

The Rx logic in the hardware picks a Rx ring for each Rx frame received
by the hardware depending on the properties like RSS, MAC and VLAN
settings configured in the hardware. These packets in the end arrive
on the Rx queue corresponding to the Rx ring in the hardware.

We are also adding some functions like bnxt_mq_rx_configure()
bnxt_free_rx_mbufs() and bnxt_free_rxq_stats() which will be used in
subsequent patches.

We are also adding hwrm_vnic_rss_cfg_* structures, which will be used
in subsequent patches to enable RSS configuration.

Signed-off-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Signed-off-by: Stephen Hurd <stephen.hurd@broadcom.com>
Reviewed-by: David Christensen <david.christensen@broadcom.com>
drivers/net/bnxt/Makefile
drivers/net/bnxt/bnxt.h
drivers/net/bnxt/bnxt_ethdev.c
drivers/net/bnxt/bnxt_rxq.c [new file with mode: 0644]
drivers/net/bnxt/bnxt_rxq.h [new file with mode: 0644]
drivers/net/bnxt/hsi_struct_def_dpdk.h

index 13a90b9..21ed71c 100644 (file)
@@ -53,6 +53,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt_filter.c
 SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt_hwrm.c
 SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt_ring.c
+SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt_rxq.c
 SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt_txq.c
 SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt_vnic.c
 
index 49aa38b..f7cf9d1 100644 (file)
@@ -142,6 +142,8 @@ struct bnxt {
        /* Default completion ring */
        struct bnxt_cp_ring_info        *def_cp_ring;
 
+       unsigned int            nr_vnics;
+
        struct bnxt_vnic_info   *vnic_info;
        STAILQ_HEAD(, bnxt_vnic_info)   free_vnic_list;
 
index 77a6d92..7e7d1ab 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "bnxt.h"
 #include "bnxt_hwrm.h"
+#include "bnxt_rxq.h"
 #include "bnxt_txq.h"
 
 #define DRV_MODULE_NAME                "bnxt"
@@ -186,6 +187,8 @@ static struct eth_dev_ops bnxt_dev_ops = {
        .dev_infos_get = bnxt_dev_info_get_op,
        .dev_close = bnxt_dev_close_op,
        .dev_configure = bnxt_dev_configure_op,
+       .rx_queue_setup = bnxt_rx_queue_setup_op,
+       .rx_queue_release = bnxt_rx_queue_release_op,
        .tx_queue_setup = bnxt_tx_queue_setup_op,
        .tx_queue_release = bnxt_tx_queue_release_op,
 };
diff --git a/drivers/net/bnxt/bnxt_rxq.c b/drivers/net/bnxt/bnxt_rxq.c
new file mode 100644 (file)
index 0000000..d5c3173
--- /dev/null
@@ -0,0 +1,287 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) Broadcom Limited.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Broadcom Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+
+#include <rte_malloc.h>
+
+#include "bnxt.h"
+#include "bnxt_filter.h"
+#include "bnxt_hwrm.h"
+#include "bnxt_ring.h"
+#include "bnxt_rxq.h"
+#include "bnxt_vnic.h"
+#include "hsi_struct_def_dpdk.h"
+
+/*
+ * RX Queues
+ */
+
+void bnxt_free_rxq_stats(struct bnxt_rx_queue *rxq)
+{
+       struct bnxt_cp_ring_info *cpr = rxq->cp_ring;
+
+       /* 'Unreserve' rte_memzone */
+
+       if (cpr->hw_stats)
+               cpr->hw_stats = NULL;
+}
+
+int bnxt_mq_rx_configure(struct bnxt *bp)
+{
+       struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf;
+       unsigned int i, j, nb_q_per_grp, ring_idx;
+       int start_grp_id, end_grp_id, rc = 0;
+       struct bnxt_vnic_info *vnic;
+       struct bnxt_filter_info *filter;
+       struct bnxt_rx_queue *rxq;
+
+       bp->nr_vnics = 0;
+
+       /* Single queue mode */
+       if (bp->rx_cp_nr_rings < 2) {
+               vnic = bnxt_alloc_vnic(bp);
+               if (!vnic) {
+                       RTE_LOG(ERR, PMD, "VNIC alloc failed\n");
+                       rc = -ENOMEM;
+                       goto err_out;
+               }
+               STAILQ_INSERT_TAIL(&bp->ff_pool[0], vnic, next);
+               bp->nr_vnics++;
+
+               rxq = bp->eth_dev->data->rx_queues[0];
+               rxq->vnic = vnic;
+
+               vnic->func_default = true;
+               vnic->ff_pool_idx = 0;
+               vnic->start_grp_id = 1;
+               vnic->end_grp_id = vnic->start_grp_id +
+                                  bp->rx_cp_nr_rings - 1;
+               filter = bnxt_alloc_filter(bp);
+               if (!filter) {
+                       RTE_LOG(ERR, PMD, "L2 filter alloc failed\n");
+                       rc = -ENOMEM;
+                       goto err_out;
+               }
+               STAILQ_INSERT_TAIL(&vnic->filter, filter, next);
+               goto out;
+       }
+
+       /* Multi-queue mode */
+       if (dev_conf->rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG) {
+               /* VMDq ONLY, VMDq+RSS, VMDq+DCB, VMDq+DCB+RSS */
+               enum rte_eth_nb_pools pools;
+
+               switch (dev_conf->rxmode.mq_mode) {
+               case ETH_MQ_RX_VMDQ_RSS:
+               case ETH_MQ_RX_VMDQ_ONLY:
+                       {
+                               const struct rte_eth_vmdq_rx_conf *conf =
+                                   &dev_conf->rx_adv_conf.vmdq_rx_conf;
+
+                               /* ETH_8/64_POOLs */
+                               pools = conf->nb_queue_pools;
+                               break;
+                       }
+               default:
+                       RTE_LOG(ERR, PMD, "Unsupported mq_mod %d\n",
+                               dev_conf->rxmode.mq_mode);
+                       rc = -EINVAL;
+                       goto err_out;
+               }
+               /* For each pool, allocate MACVLAN CFA rule & VNIC */
+               if (!pools) {
+                       RTE_LOG(ERR, PMD,
+                               "VMDq pool not set, defaulted to 64\n");
+                       pools = ETH_64_POOLS;
+               }
+               nb_q_per_grp = bp->rx_cp_nr_rings / pools;
+               start_grp_id = 1;
+               end_grp_id = start_grp_id + nb_q_per_grp - 1;
+
+               ring_idx = 0;
+               for (i = 0; i < pools; i++) {
+                       vnic = bnxt_alloc_vnic(bp);
+                       if (!vnic) {
+                               RTE_LOG(ERR, PMD,
+                                       "VNIC alloc failed\n");
+                               rc = -ENOMEM;
+                               goto err_out;
+                       }
+                       STAILQ_INSERT_TAIL(&bp->ff_pool[i], vnic, next);
+                       bp->nr_vnics++;
+
+                       for (j = 0; j < nb_q_per_grp; j++, ring_idx++) {
+                               rxq = bp->eth_dev->data->rx_queues[ring_idx];
+                               rxq->vnic = vnic;
+                       }
+                       if (i == 0)
+                               vnic->func_default = true;
+                       vnic->ff_pool_idx = i;
+                       vnic->start_grp_id = start_grp_id;
+                       vnic->end_grp_id = end_grp_id;
+
+                       filter = bnxt_alloc_filter(bp);
+                       if (!filter) {
+                               RTE_LOG(ERR, PMD,
+                                       "L2 filter alloc failed\n");
+                               rc = -ENOMEM;
+                               goto err_out;
+                       }
+                       /*
+                        * TODO: Configure & associate CFA rule for
+                        * each VNIC for each VMDq with MACVLAN, MACVLAN+TC
+                        */
+                       STAILQ_INSERT_TAIL(&vnic->filter, filter, next);
+
+                       start_grp_id = end_grp_id + 1;
+                       end_grp_id += nb_q_per_grp;
+               }
+               goto out;
+       }
+
+       /* Non-VMDq mode - RSS, DCB, RSS+DCB */
+       /* Init default VNIC for RSS or DCB only */
+       vnic = bnxt_alloc_vnic(bp);
+       if (!vnic) {
+               RTE_LOG(ERR, PMD, "VNIC alloc failed\n");
+               rc = -ENOMEM;
+               goto err_out;
+       }
+       /* Partition the rx queues for the single pool */
+       for (i = 0; i < bp->rx_cp_nr_rings; i++) {
+               rxq = bp->eth_dev->data->rx_queues[i];
+               rxq->vnic = vnic;
+       }
+       STAILQ_INSERT_TAIL(&bp->ff_pool[0], vnic, next);
+       bp->nr_vnics++;
+
+       vnic->func_default = true;
+       vnic->ff_pool_idx = 0;
+       vnic->start_grp_id = 1;
+       vnic->end_grp_id = vnic->start_grp_id +
+                          bp->rx_cp_nr_rings - 1;
+       filter = bnxt_alloc_filter(bp);
+       if (!filter) {
+               RTE_LOG(ERR, PMD, "L2 filter alloc failed\n");
+               rc = -ENOMEM;
+               goto err_out;
+       }
+       STAILQ_INSERT_TAIL(&vnic->filter, filter, next);
+
+       if (dev_conf->rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG)
+               vnic->hash_type =
+                       HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_IPV4 |
+                       HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_IPV6;
+
+out:
+       return rc;
+
+err_out:
+       /* Free allocated vnic/filters */
+
+       return rc;
+}
+
+static void bnxt_rx_queue_release_mbufs(struct bnxt_rx_queue *rxq __rte_unused)
+{
+       /* TODO: Requires interaction with TX ring */
+}
+
+void bnxt_free_rx_mbufs(struct bnxt *bp)
+{
+       struct bnxt_rx_queue *rxq;
+       int i;
+
+       for (i = 0; i < (int)bp->rx_nr_rings; i++) {
+               rxq = bp->rx_queues[i];
+               bnxt_rx_queue_release_mbufs(rxq);
+       }
+}
+
+void bnxt_rx_queue_release_op(void *rx_queue)
+{
+       struct bnxt_rx_queue *rxq = (struct bnxt_rx_queue *)rx_queue;
+
+       if (rxq) {
+               bnxt_rx_queue_release_mbufs(rxq);
+
+               /* TODO: Free ring and stats here */
+
+               rte_free(rxq);
+       }
+}
+
+int bnxt_rx_queue_setup_op(struct rte_eth_dev *eth_dev,
+                              uint16_t queue_idx,
+                              uint16_t nb_desc,
+                              unsigned int socket_id,
+                              const struct rte_eth_rxconf *rx_conf,
+                              struct rte_mempool *mp)
+{
+       struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private;
+       struct bnxt_rx_queue *rxq;
+
+       if (!nb_desc || nb_desc > MAX_RX_DESC_CNT) {
+               RTE_LOG(ERR, PMD, "nb_desc %d is invalid", nb_desc);
+               return -EINVAL;
+       }
+
+       if (eth_dev->data->rx_queues) {
+               rxq = eth_dev->data->rx_queues[queue_idx];
+               if (rxq)
+                       bnxt_rx_queue_release_op(rxq);
+       }
+       rxq = rte_zmalloc_socket("bnxt_rx_queue", sizeof(struct bnxt_rx_queue),
+                                RTE_CACHE_LINE_SIZE, socket_id);
+       if (!rxq) {
+               RTE_LOG(ERR, PMD, "bnxt_rx_queue allocation failed!");
+               return -ENOMEM;
+       }
+       rxq->bp = bp;
+       rxq->mb_pool = mp;
+       rxq->nb_rx_desc = nb_desc;
+       rxq->rx_free_thresh = rx_conf->rx_free_thresh;
+
+       /* TODO: Initialize ring structure */
+
+       rxq->queue_id = queue_idx;
+       rxq->port_id = eth_dev->data->port_id;
+       rxq->crc_len = (uint8_t)((eth_dev->data->dev_conf.rxmode.hw_strip_crc) ?
+                               0 : ETHER_CRC_LEN);
+
+       eth_dev->data->rx_queues[queue_idx] = rxq;
+       /* TODO: Allocate RX ring hardware descriptors */
+
+       return 0;
+}
diff --git a/drivers/net/bnxt/bnxt_rxq.h b/drivers/net/bnxt/bnxt_rxq.h
new file mode 100644 (file)
index 0000000..9554329
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) Broadcom Limited.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Broadcom Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _BNXT_RQX_H_
+#define _BNXT_RQX_H_
+
+struct bnxt;
+struct bnxt_rx_ring_info;
+struct bnxt_cp_ring_info;
+struct bnxt_rx_queue {
+       struct rte_mempool      *mb_pool; /* mbuf pool for RX ring */
+       struct rte_mbuf         *pkt_first_seg; /* 1st seg of pkt */
+       struct rte_mbuf         *pkt_last_seg; /* Last seg of pkt */
+       uint64_t                mbuf_initializer; /* val to init mbuf */
+       uint16_t                nb_rx_desc; /* num of RX desc */
+       uint16_t                rx_tail; /* cur val of RDT register */
+       uint16_t                nb_rx_hold; /* num held free RX desc */
+       uint16_t                rx_free_thresh; /* max free RX desc to hold */
+       uint16_t                queue_id; /* RX queue index */
+       uint16_t                reg_idx; /* RX queue register index */
+       uint8_t                 port_id; /* Device port identifier */
+       uint8_t                 crc_len; /* 0 if CRC stripped, 4 otherwise */
+
+       struct bnxt             *bp;
+       struct bnxt_vnic_info   *vnic;
+
+       uint32_t                        rx_buf_size;
+       uint32_t                        rx_buf_use_size;  /* useable size */
+       struct bnxt_rx_ring_info        *rx_ring;
+       struct bnxt_cp_ring_info        *cp_ring;
+};
+
+void bnxt_free_rxq_stats(struct bnxt_rx_queue *rxq);
+int bnxt_mq_rx_configure(struct bnxt *bp);
+void bnxt_rx_queue_release_op(void *rx_queue);
+int bnxt_rx_queue_setup_op(struct rte_eth_dev *eth_dev,
+                              uint16_t queue_idx,
+                              uint16_t nb_desc,
+                              unsigned int socket_id,
+                              const struct rte_eth_rxconf *rx_conf,
+                              struct rte_mempool *mp);
+void bnxt_free_rx_mbufs(struct bnxt *bp);
+
+#endif
index ca42a87..bbec5bb 100644 (file)
@@ -1897,6 +1897,127 @@ struct hwrm_queue_qportcfg_input {
        uint16_t unused_0;
 } __attribute__((packed));
 
+/* hwrm_vnic_rss_cfg */
+/* Description: This function is used to enable RSS configuration. */
+
+/* Input (48 bytes) */
+struct hwrm_vnic_rss_cfg_input {
+       /*
+        * This value indicates what type of request this is. The format for the
+        * rest of the command is determined by this field.
+        */
+       uint16_t req_type;
+
+       /*
+        * This value indicates the what completion ring the request will be
+        * optionally completed on. If the value is -1, then no CR completion
+        * will be generated. Any other value must be a valid CR ring_id value
+        * for this function.
+        */
+       uint16_t cmpl_ring;
+
+       /* This value indicates the command sequence number. */
+       uint16_t seq_id;
+
+       /*
+        * Target ID of this command. 0x0 - 0xFFF8 - Used for function ids
+        * 0xFFF8 - 0xFFFE - Reserved for internal processors 0xFFFF - HWRM
+        */
+       uint16_t target_id;
+
+       /*
+        * This is the host address where the response will be written when the
+        * request is complete. This area must be 16B aligned and must be
+        * cleared to zero before the request is made.
+        */
+       uint64_t resp_addr;
+
+       /*
+        * When this bit is '1', the RSS hash shall be computed over source and
+        * destination IPv4 addresses of IPv4 packets.
+        */
+       #define HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_IPV4          UINT32_C(0x1)
+       /*
+        * When this bit is '1', the RSS hash shall be computed over
+        * source/destination IPv4 addresses and source/destination ports of
+        * TCP/IPv4 packets.
+        */
+       #define HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_TCP_IPV4      UINT32_C(0x2)
+       /*
+        * When this bit is '1', the RSS hash shall be computed over
+        * source/destination IPv4 addresses and source/destination ports of
+        * UDP/IPv4 packets.
+        */
+       #define HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_UDP_IPV4      UINT32_C(0x4)
+       /*
+        * When this bit is '1', the RSS hash shall be computed over source and
+        * destination IPv4 addresses of IPv6 packets.
+        */
+       #define HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_IPV6          UINT32_C(0x8)
+       /*
+        * When this bit is '1', the RSS hash shall be computed over
+        * source/destination IPv6 addresses and source/destination ports of
+        * TCP/IPv6 packets.
+        */
+       #define HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_TCP_IPV6      UINT32_C(0x10)
+       /*
+        * When this bit is '1', the RSS hash shall be computed over
+        * source/destination IPv6 addresses and source/destination ports of
+        * UDP/IPv6 packets.
+        */
+       #define HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_UDP_IPV6      UINT32_C(0x20)
+       uint32_t hash_type;
+
+       uint32_t unused_0;
+
+       /* This is the address for rss ring group table */
+       uint64_t ring_grp_tbl_addr;
+
+       /* This is the address for rss hash key table */
+       uint64_t hash_key_tbl_addr;
+
+       /* Index to the rss indirection table. */
+       uint16_t rss_ctx_idx;
+
+       uint16_t unused_1[3];
+} __attribute__((packed));
+
+/* Output (16 bytes) */
+struct hwrm_vnic_rss_cfg_output {
+       /*
+        * Pass/Fail or error type Note: receiver to verify the in parameters,
+        * and fail the call with an error when appropriate
+        */
+       uint16_t error_code;
+
+       /* This field returns the type of original request. */
+       uint16_t req_type;
+
+       /* This field provides original sequence number of the command. */
+       uint16_t seq_id;
+
+       /*
+        * This field is the length of the response in bytes. The last byte of
+        * the response is a valid flag that will read as '1' when the command
+        * has been completely written to memory.
+        */
+       uint16_t resp_len;
+
+       uint32_t unused_0;
+       uint8_t unused_1;
+       uint8_t unused_2;
+       uint8_t unused_3;
+
+       /*
+        * This field is used in Output records to indicate that the output is
+        * completely written to RAM. This field should be read as '1' to
+        * indicate that the output has been completely written. When writing a
+        * command completion or response to an internal processor, the order of
+        * writes has to be such that this field is written last.
+        */
+       uint8_t valid;
+} __attribute__((packed));
+
 /* Output (32 bytes) */
 struct hwrm_queue_qportcfg_output {
        /*