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 */
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;
}
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
struct gve_events events;
/** Scratch buffer */
struct gve_scratch scratch;
+ /** Supported options */
+ uint32_t options;
/** Transmit queue */
struct gve_queue tx;