From: Michael Brown Date: Thu, 25 Sep 2025 13:42:19 +0000 (+0100) Subject: [gve] Parse option list returned in device descriptor X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ee9aea7893b7e1e08b591c06f18b24940198e7c5;p=thirdparty%2Fipxe.git [gve] Parse option list returned in device descriptor 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 --- diff --git a/src/drivers/net/gve.c b/src/drivers/net/gve.c index 20ea6b97b..bfce6016f 100644 --- a/src/drivers/net/gve.c +++ b/src/drivers/net/gve.c @@ -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; } diff --git a/src/drivers/net/gve.h b/src/drivers/net/gve.h index 881c25fe2..704c1cbe1 100644 --- a/src/drivers/net/gve.h +++ b/src/drivers/net/gve.h @@ -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;