]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[gve] Parse option list returned in device descriptor
authorMichael Brown <mcb30@ipxe.org>
Thu, 25 Sep 2025 13:42:19 +0000 (14:42 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 26 Sep 2025 11:02:03 +0000 (12:02 +0100)
Provide space for the device to return its list of supported options.
Parse the option list and record the existence of each option in a
support bitmask.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/net/gve.c
src/drivers/net/gve.h

index 20ea6b97bf2e71d96c20a049964d79a21238f652..bfce6016f8930e2e1710ef602311cbb4b0ace59a 100644 (file)
@@ -420,6 +420,12 @@ static int gve_describe ( struct gve_nic *gve ) {
        struct net_device *netdev = gve->netdev;
        struct gve_device_descriptor *desc = &gve->scratch.buf->desc;
        union gve_admin_command *cmd;
+       struct gve_option *opt;
+       unsigned int count;
+       unsigned int id;
+       size_t offset;
+       size_t max;
+       size_t len;
        int rc;
 
        /* Construct request */
@@ -451,6 +457,38 @@ static int gve_describe ( struct gve_nic *gve ) {
               gve, eth_ntoa ( netdev->hw_addr ),
               inet_ntoa ( desc->mac.in ), netdev->mtu );
 
+       /* Parse options */
+       count = be16_to_cpu ( desc->opt_count );
+       max = be16_to_cpu ( desc->len );
+       gve->options = 0;
+       for ( offset = offsetof ( typeof ( *desc ), opts ) ; count ;
+             count--, offset += len ) {
+
+               /* Check space for option header */
+               if ( ( offset + sizeof ( *opt ) ) > max ) {
+                       DBGC ( gve, "GVE %p underlength option at +%#02zx:\n",
+                              gve, offset );
+                       DBGC_HDA ( gve, 0, desc, sizeof ( *desc ) );
+                       return -EINVAL;
+               }
+               opt = ( ( ( void * ) desc ) + offset );
+
+               /* Check space for option body */
+               len = ( sizeof ( *opt ) + be16_to_cpu ( opt->len ) );
+               if ( ( offset + len ) > max ) {
+                       DBGC ( gve, "GVE %p malformed option at +%#02zx:\n",
+                              gve, offset );
+                       DBGC_HDA ( gve, 0, desc, sizeof ( *desc ) );
+                       return -EINVAL;
+               }
+
+               /* Record option as supported */
+               id = be16_to_cpu ( opt->id );
+               if ( id < ( 8 * sizeof ( gve->options ) ) )
+                       gve->options |= ( 1 << id );
+       }
+       DBGC ( gve, "GVE %p supports options %#08x\n", gve, gve->options );
+
        return 0;
 }
 
index 881c25fe2489621dc1fea52c4541856b7914d63b..704c1cbe1566fd096d95851172509d781e9297fc 100644 (file)
@@ -155,10 +155,48 @@ struct gve_device_descriptor {
        uint8_t reserved_c[4];
        /** MAC address */
        struct google_mac mac;
+       /** Number of device options */
+       uint16_t opt_count;
+       /** Total length (including this header) */
+       uint16_t len;
        /** Reserved */
-       uint8_t reserved_d[10];
+       uint8_t reserved_d[6];
+       /** Space for options
+        *
+        * There is no specified upper limit, and no negotiation
+        * mechanism for the amount of space required.  We allow space
+        * for seems like a reasonable number of options.
+        */
+       uint8_t opts[216];
+} __attribute__ (( packed ));
+
+/** Device option header */
+struct gve_option {
+       /** Option ID */
+       uint16_t id;
+       /** Length (excluding this header) */
+       uint16_t len;
+       /** Required feature mask
+        *
+        * The purpose of this field is remarkably unclear.  The Linux
+        * kernel driver does define enum gve_dev_opt_req_feat_mask,
+        * but every member of this enum has a zero value.
+        */
+       uint32_t required;
 } __attribute__ (( packed ));
 
+/** In-order descriptor queues with raw DMA addressing */
+#define GVE_OPT_GQI_RDA 0x02
+
+/** In-order descriptor queues with queue page list addressing */
+#define GVE_OPT_GQI_QPL 0x03
+
+/** Out-of-order descriptor queues with raw DMA addressing */
+#define GVE_OPT_DQO_RDA 0x04
+
+/** Out-of-order descriptor queues with queue page list addressing */
+#define GVE_OPT_DQO_QPL 0x07
+
 /** Configure device resources command */
 #define GVE_ADMIN_CONFIGURE 0x0002
 
@@ -663,6 +701,8 @@ struct gve_nic {
        struct gve_events events;
        /** Scratch buffer */
        struct gve_scratch scratch;
+       /** Supported options */
+       uint32_t options;
 
        /** Transmit queue */
        struct gve_queue tx;