diff options
| author | Simon Rettberg | 2026-01-28 12:53:53 +0100 |
|---|---|---|
| committer | Simon Rettberg | 2026-01-28 12:53:53 +0100 |
| commit | 8e82785c584dc13e20f9229decb95bd17bbe9cd1 (patch) | |
| tree | a8b359e59196be5b2e3862bed189107f4bc9975f /src/drivers/net/gve.h | |
| parent | Merge branch 'master' into openslx (diff) | |
| parent | [prefix] Make unlzma.S compatible with 386 class CPUs (diff) | |
| download | ipxe-openslx.tar.gz ipxe-openslx.tar.xz ipxe-openslx.zip | |
Merge branch 'master' into openslxopenslx
Diffstat (limited to 'src/drivers/net/gve.h')
| -rw-r--r-- | src/drivers/net/gve.h | 915 |
1 files changed, 915 insertions, 0 deletions
diff --git a/src/drivers/net/gve.h b/src/drivers/net/gve.h new file mode 100644 index 000000000..d352306ef --- /dev/null +++ b/src/drivers/net/gve.h @@ -0,0 +1,915 @@ +#ifndef _GVE_H +#define _GVE_H + +/** @file + * + * Google Virtual Ethernet network driver + * + * The Google Virtual Ethernet NIC (GVE or gVNIC) is found only in + * Google Cloud instances. There is essentially zero documentation + * available beyond the mostly uncommented source code in the Linux + * kernel. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> +#include <ipxe/dma.h> +#include <ipxe/pci.h> +#include <ipxe/pcimsix.h> +#include <ipxe/in.h> +#include <ipxe/process.h> +#include <ipxe/retry.h> + +struct gve_nic; + +/** + * A Google Cloud MAC address + * + * Google Cloud locally assigned MAC addresses encode the local IPv4 + * address in the trailing 32 bits, presumably as a performance + * optimisation to allow ARP resolution to be skipped by a suitably + * aware network stack. + */ +struct google_mac { + /** Reserved */ + uint8_t reserved[2]; + /** Local IPv4 address */ + struct in_addr in; +} __attribute__ (( packed )); + +/** Page size */ +#define GVE_PAGE_SIZE 0x1000 + +/** + * Address alignment + * + * All DMA data structure base addresses seem to need to be aligned to + * a page boundary. (This is not documented anywhere, but is inferred + * from existing source code and experimentation.) + */ +#define GVE_ALIGN GVE_PAGE_SIZE + +/** Configuration BAR */ +#define GVE_CFG_BAR PCI_BASE_ADDRESS_0 + +/** + * Configuration BAR size + * + * All registers within the configuration BAR are big-endian. + */ +#define GVE_CFG_SIZE 0x1000 + +/** Device status */ +#define GVE_CFG_DEVSTAT 0x0000 +#define GVE_CFG_DEVSTAT_RESET 0x00000010UL /**< Device is reset */ + +/** Driver status */ +#define GVE_CFG_DRVSTAT 0x0004 +#define GVE_CFG_DRVSTAT_RUN 0x00000001UL /**< Run admin queue */ + +/** Maximum time to wait for reset */ +#define GVE_RESET_MAX_WAIT_MS 500 + +/** Admin queue page frame number (for older devices) */ +#define GVE_CFG_ADMIN_PFN 0x0010 + +/** Admin queue doorbell */ +#define GVE_CFG_ADMIN_DB 0x0014 + +/** Admin queue event counter */ +#define GVE_CFG_ADMIN_EVT 0x0018 + +/** Driver version (8-bit register) */ +#define GVE_CFG_VERSION 0x001f + +/** Admin queue base address high 32 bits */ +#define GVE_CFG_ADMIN_BASE_HI 0x0020 + +/** Admin queue base address low 32 bits */ +#define GVE_CFG_ADMIN_BASE_LO 0x0024 + +/** Admin queue base address length (16-bit register) */ +#define GVE_CFG_ADMIN_LEN 0x0028 + +/** Doorbell BAR */ +#define GVE_DB_BAR PCI_BASE_ADDRESS_2 + +/** + * Admin queue entry header + * + * All values within admin queue entries are big-endian. + */ +struct gve_admin_header { + /** Reserved */ + uint8_t reserved[3]; + /** Operation code */ + uint8_t opcode; + /** Status */ + uint32_t status; +} __attribute__ (( packed )); + +/** Command succeeded */ +#define GVE_ADMIN_STATUS_OK 0x00000001 + +/** Simple admin command */ +struct gve_admin_simple { + /** Header */ + struct gve_admin_header hdr; + /** ID */ + uint32_t id; +} __attribute__ (( packed )); + +/** Describe device command */ +#define GVE_ADMIN_DESCRIBE 0x0001 + +/** Describe device command */ +struct gve_admin_describe { + /** Header */ + struct gve_admin_header hdr; + /** Descriptor buffer address */ + uint64_t addr; + /** Descriptor version */ + uint32_t ver; + /** Descriptor maximum length */ + uint32_t len; +} __attribute__ (( packed )); + +/** Device descriptor version */ +#define GVE_ADMIN_DESCRIBE_VER 1 + +/** Device descriptor */ +struct gve_device_descriptor { + /** Reserved */ + uint8_t reserved_a[10]; + /** Number of transmit queue entries */ + uint16_t tx_count; + /** Number of receive queue entries */ + uint16_t rx_count; + /** Reserved */ + uint8_t reserved_b[2]; + /** Maximum transmit unit */ + uint16_t mtu; + /** Number of event counters */ + uint16_t counters; + /** Reserved */ + 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[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 + +/** Configure device resources command */ +struct gve_admin_configure { + /** Header */ + struct gve_admin_header hdr; + /** Event counter array */ + uint64_t events; + /** IRQ doorbell address */ + uint64_t irqs; + /** Number of event counters */ + uint32_t num_events; + /** Number of IRQ doorbells */ + uint32_t num_irqs; + /** IRQ doorbell stride */ + uint32_t irq_stride; + /** MSI-X base index */ + uint32_t msix_base; + /** Descriptor queue format */ + uint8_t format; + /** Reserved */ + uint8_t reserved[7]; +} __attribute__ (( packed )); + +/** Descriptor queue format */ +#define GVE_FORMAT( mode ) ( (mode) + 1 ) + +/** Register page list command */ +#define GVE_ADMIN_REGISTER 0x0003 + +/** Register page list command */ +struct gve_admin_register { + /** Header */ + struct gve_admin_header hdr; + /** Page list ID */ + uint32_t id; + /** Number of pages */ + uint32_t count; + /** Address list address */ + uint64_t addr; + /** Page size */ + uint64_t size; +} __attribute__ (( packed )); + +/** + * Maximum number of pages per queue + * + * This is a policy decision. Must be sufficient to allow for both + * the transmit and receive queue fill levels. + */ +#define GVE_QPL_MAX 32 + +/** Page list */ +struct gve_pages { + /** Page address */ + uint64_t addr[GVE_QPL_MAX]; +} __attribute__ (( packed )); + +/** Unregister page list command */ +#define GVE_ADMIN_UNREGISTER 0x0004 + +/** Create transmit queue command */ +#define GVE_ADMIN_CREATE_TX 0x0005 + +/** Create transmit queue command */ +struct gve_admin_create_tx { + /** Header */ + struct gve_admin_header hdr; + /** Queue ID */ + uint32_t id; + /** Reserved */ + uint8_t reserved_a[4]; + /** Queue resources address */ + uint64_t res; + /** Descriptor ring address */ + uint64_t desc; + /** Queue page list ID */ + uint32_t qpl_id; + /** Notification channel ID */ + uint32_t notify_id; + /** Completion ring address */ + uint64_t cmplt; + /** Number of descriptor ring entries */ + uint16_t desc_count; + /** Number of completion ring entries */ + uint16_t cmplt_count; + /** Reserved */ + uint8_t reserved_b[4]; +} __attribute__ (( packed )); + +/** Create receive queue command */ +#define GVE_ADMIN_CREATE_RX 0x0006 + +/** Create receive queue command */ +struct gve_admin_create_rx { + /** Header */ + struct gve_admin_header hdr; + /** Queue ID */ + uint32_t id; + /** Index */ + uint32_t index; + /** Reserved */ + uint8_t reserved_a[4]; + /** Notification channel ID */ + uint32_t notify_id; + /** Queue resources address */ + uint64_t res; + /** Completion ring address */ + uint64_t cmplt; + /** Descriptor ring address */ + uint64_t desc; + /** Queue page list ID */ + uint32_t qpl_id; + /** Number of descriptor ring entries */ + uint16_t desc_count; + /** Packet buffer size */ + uint16_t bufsz; + /** Number of completion ring entries */ + uint16_t cmplt_count; + /** Reserved */ + uint8_t reserved[6]; +} __attribute__ (( packed )); + +/** Destroy transmit queue command */ +#define GVE_ADMIN_DESTROY_TX 0x0007 + +/** Destroy receive queue command */ +#define GVE_ADMIN_DESTROY_RX 0x0008 + +/** Deconfigure device resources command */ +#define GVE_ADMIN_DECONFIGURE 0x0009 + +/** An admin queue command */ +union gve_admin_command { + /** Header */ + struct gve_admin_header hdr; + /** Simple command */ + struct gve_admin_simple simple; + /** Describe device */ + struct gve_admin_describe desc; + /** Configure device resources */ + struct gve_admin_configure conf; + /** Register page list */ + struct gve_admin_register reg; + /** Create transmit queue */ + struct gve_admin_create_tx create_tx; + /** Create receive queue */ + struct gve_admin_create_rx create_rx; + /** Padding */ + uint8_t pad[64]; +}; + +/** + * Number of admin queue commands + * + * This is theoretically a policy decision. However, older revisions + * of the hardware seem to have only the "admin queue page frame + * number" register and no "admin queue length" register, with the + * implication that the admin queue must be exactly one page in + * length. + * + * Choose to use a one page (4kB) admin queue for both older and newer + * versions of the hardware, to minimise variability. + */ +#define GVE_ADMIN_COUNT ( GVE_PAGE_SIZE / sizeof ( union gve_admin_command ) ) + +/** Admin queue */ +struct gve_admin { + /** Commands */ + union gve_admin_command *cmd; + /** Producer counter */ + uint32_t prod; + /** DMA mapping */ + struct dma_mapping map; +}; + +/** Scratch buffer for admin queue commands */ +struct gve_scratch { + /** Buffer contents */ + union { + /** Device descriptor */ + struct gve_device_descriptor desc; + /** Page address list */ + struct gve_pages pages; + } *buf; + /** DMA mapping */ + struct dma_mapping map; +}; + +/** + * An event counter + * + * Written by the device to indicate completions. The device chooses + * which counter to use for each transmit queue, and stores the index + * of the chosen counter in the queue resources. + */ +struct gve_event { + /** Number of events that have occurred */ + volatile uint32_t count; +} __attribute__ (( packed )); + +/** Event counter array */ +struct gve_events { + /** Event counters */ + struct gve_event *event; + /** DMA mapping */ + struct dma_mapping map; + /** Actual number of event counters */ + unsigned int count; +}; + +/** An interrupt channel */ +struct gve_irq { + /** Interrupt doorbell index (within doorbell BAR) */ + uint32_t db_idx; + /** Reserved */ + uint8_t reserved[60]; +} __attribute__ (( packed )); + +/** + * Number of interrupt channels + * + * We tell the device how many interrupt channels we have provided via + * the "configure device resources" admin queue command. The device + * will accept being given zero interrupt channels, but will + * subsequently fail to create more than a single queue (either + * transmit or receive). + * + * There is, of course, no documentation indicating how may interrupt + * channels actually need to be provided. In the absence of evidence + * to the contrary, assume that two channels (one for transmit, one + * for receive) will be sufficient. + */ +#define GVE_IRQ_COUNT 2 + +/** Interrupt channel array */ +struct gve_irqs { + /** Interrupt channels */ + struct gve_irq *irq; + /** DMA mapping */ + struct dma_mapping map; + /** Interrupt doorbells */ + volatile uint32_t *db[GVE_IRQ_COUNT]; +}; + +/** Disable in-order queue interrupt */ +#define GVE_GQI_IRQ_DISABLE 0x40000000UL + +/** Rearm out-of-order queue interrupt */ +#define GVE_DQO_IRQ_REARM 0x00000019UL + +/** + * Queue resources + * + * Written by the device to indicate the indices of the chosen event + * counter and descriptor doorbell register. + * + * This appears to be a largely pointless data structure: the relevant + * information is static for the lifetime of the queue and could + * trivially have been returned in the response for the "create + * transmit/receive queue" command, instead of requiring yet another + * page-aligned coherent DMA buffer allocation. + */ +struct gve_resources { + /** Descriptor doorbell index (within doorbell BAR) */ + uint32_t db_idx; + /** Event counter index (within event counter array) */ + uint32_t evt_idx; + /** Reserved */ + uint8_t reserved[56]; +} __attribute__ (( packed )); + +/** + * Queue data buffer size + * + * In theory, we may specify the size of receive buffers. However, + * the original version of the device seems not to have a parameter + * for this, and assumes the use of half-page (2kB) buffers. Choose + * to use this as the buffer size, on the assumption that older + * devices will not support any other buffer size. + */ +#define GVE_BUF_SIZE ( GVE_PAGE_SIZE / 2 ) + +/** Number of data buffers per page */ +#define GVE_BUF_PER_PAGE ( GVE_PAGE_SIZE / GVE_BUF_SIZE ) + +/** + * Queue page list + * + * The device uses preregistered pages for fast-path DMA operations + * (i.e. transmit and receive buffers). A list of device addresses + * for each page must be registered before the transmit or receive + * queue is created, and cannot subsequently be modified. + * + * The Linux driver allocates pages as DMA_TO_DEVICE or + * DMA_FROM_DEVICE as appropriate, and uses dma_sync_single_for_cpu() + * etc to ensure that data is copied to/from bounce buffers as needed. + * + * Unfortunately there is no such sync operation available within our + * DMA API, since we are constrained by the limitations imposed by + * EFI_PCI_IO_PROTOCOL. There is no way to synchronise a buffer + * without also [un]mapping it, and no way to force the reuse of the + * same device address for a subsequent remapping. We are therefore + * constrained to use only DMA-coherent buffers, since this is the + * only way we can repeatedly reuse the same device address. + * + * Newer versions of the gVNIC device support "raw DMA addressing + * (RDA)", which is essentially a prebuilt queue page list covering + * the whole of the guest address space. Unfortunately we cannot rely + * on this, since older versions will not support it. + * + * Experimentation suggests that the device will accept a request to + * create a queue page list covering the whole of the guest address + * space via two giant "pages" of 2^63 bytes each. However, + * experimentation also suggests that the device will accept any old + * garbage value as the "page size". In the total absence of any + * documentation, it is probably unsafe to conclude that the device is + * bothering to look at or respect the "page size" parameter: it is + * most likely just presuming the use of 4kB pages. + */ +struct gve_qpl { + /** Page addresses */ + void *data; + /** Page mapping */ + struct dma_mapping map; + /** Number of pages */ + unsigned int count; + /** Queue page list ID */ + unsigned int id; + /** Queue page list base device address + * + * This will be zero in the GQI-QPL operating mode, or the DMA + * address of the first page in any other operating mode. + * (Despite its name, DQO-QPL still requires the use of raw + * DMA addresses in transmit and receive descriptors.) + */ + physaddr_t base; +}; + +/** Raw DMA addressing queue page list ID */ +#define GVE_RAW_QPL 0xffffffff + +/** + * Maximum number of transmit buffers + * + * This is a policy decision. + */ +#define GVE_TX_FILL 8 + +/** Transmit queue page list ID */ +#define GVE_TX_QPL 0x18ae5458 + +/** Tranmsit queue interrupt channel */ +#define GVE_TX_IRQ 0 + +/** A transmit or receive buffer descriptor */ +struct gve_buffer { + /** Address (within queue page list address space) */ + uint64_t addr; +} __attribute__ (( packed )); + +/** An in-order transmit descriptor */ +struct gve_gqi_tx_descriptor { + /** Type */ + uint8_t type; + /** Reserved */ + uint8_t reserved_a[2]; + /** Number of descriptors in this packet */ + uint8_t count; + /** Total length of this packet */ + uint16_t total; + /** Length of this descriptor */ + uint16_t len; + /** Buffer descriptor */ + struct gve_buffer buf; +} __attribute__ (( packed )); + +/** Start of packet transmit descriptor type */ +#define GVE_GQI_TX_TYPE_START 0x00 + +/** Continuation of packet transmit descriptor type */ +#define GVE_GQI_TX_TYPE_CONT 0x20 + +/** An out-of-order transmit tag + * + * From the hardware perspective, this is an opaque 15-bit (sic) value + * that is simply copied from the descriptor to the corresponding + * completion. + */ +struct gve_dqo_tx_tag { + /** Buffer index within queue page list */ + uint8_t id; + /** Number of descriptors covered by this completion + * + * Note that this is a 7-bit quantity: the high bit may be + * (ab)used by the hardware to indicate that a completion is a + * terminologically undefined "miss" completion. + */ + int8_t count; +} __attribute__ (( packed )); + +/** An out-of-order transmit descriptor */ +struct gve_dqo_tx_descriptor { + /** Buffer descriptor */ + struct gve_buffer buf; + /** Descriptor type and flags */ + uint8_t type; + /** Reserved */ + uint8_t reserved_a[3]; + /** Tag */ + struct gve_dqo_tx_tag tag; + /** Length of this descriptor */ + uint16_t len; +} __attribute__ (( packed )); + +/** Normal packet transmit descriptor type */ +#define GVE_DQO_TX_TYPE_PACKET 0x0c + +/** Last transmit descriptor in a packet */ +#define GVE_DQO_TX_TYPE_LAST 0x20 + +/** An out-of-order transmit completion */ +struct gve_dqo_tx_completion { + /** Reserved */ + uint8_t reserved_a[1]; + /** Completion flags */ + uint8_t flags; + /** Tag */ + struct gve_dqo_tx_tag tag; + /** Reserved */ + uint8_t reserved_b[4]; +} __attribute__ (( packed )); + +/** Transmit completion packet flag */ +#define GVE_DQO_TXF_PKT 0x10 + +/** Transmit completion generation flag */ +#define GVE_DQO_TXF_GEN 0x80 + +/** + * Maximum number of receive buffers + * + * This is a policy decision. Experiments suggest that using fewer + * than 64 receive buffers leads to excessive packet drop rates on + * some instance types. + */ +#define GVE_RX_FILL 64 + +/** Receive queue page list ID */ +#define GVE_RX_QPL 0x18ae5258 + +/** Receive queue interrupt channel */ +#define GVE_RX_IRQ 1 + +/** An in-order receive descriptor */ +struct gve_gqi_rx_descriptor { + /** Buffer descriptor */ + struct gve_buffer buf; +} __attribute__ (( packed )); + +/** Receive error */ +#define GVE_GQI_RXF_ERROR 0x08 + +/** Receive packet continues into next descriptor */ +#define GVE_GQI_RXF_MORE 0x20 + +/** Receive sequence number mask */ +#define GVE_GQI_RX_SEQ_MASK 0x07 + +/** An in-order receive completion descriptor */ +struct gve_gqi_rx_completion { + /** Reserved */ + uint8_t reserved[60]; + /** Length */ + uint16_t len; + /** Flags */ + uint8_t flags; + /** Sequence number */ + uint8_t seq; +} __attribute__ (( packed )); + +/** Padding at the start of all received packets */ +#define GVE_GQI_RX_PAD 2 + +/** An out-of-order receive descriptor */ +struct gve_dqo_rx_descriptor { + /** Tag */ + uint8_t tag; + /** Reserved */ + uint8_t reserved_a[7]; + /** Buffer descriptor */ + struct gve_buffer buf; + /** Reserved */ + uint8_t reserved_b[16]; +} __attribute__ (( packed )); + +/** An out-of-order receive completion */ +struct gve_dqo_rx_completion { + /** Reserved */ + uint8_t reserved_a[1]; + /** Status */ + uint8_t status; + /** Reserved */ + uint8_t reserved_b[2]; + /** Length and generation bit */ + uint16_t len; + /** Reserved */ + uint8_t reserved_c[2]; + /** Flags */ + uint8_t flags; + /** Reserved */ + uint8_t reserved_d[3]; + /** Tag */ + uint8_t tag; + /** Reserved */ + uint8_t reserved_e[19]; +} __attribute__ (( packed )); + +/** Receive error */ +#define GVE_DQO_RXS_ERROR 0x04 + +/** Receive completion generation flag */ +#define GVE_DQO_RXL_GEN 0x4000 + +/** Last receive descriptor in a packet */ +#define GVE_DQO_RXF_LAST 0x02 + +/** Queue strides */ +struct gve_queue_stride { + /** Descriptor ring stride */ + uint8_t desc; + /** Completion ring stride */ + uint8_t cmplt; +}; + +/** A descriptor queue */ +struct gve_queue { + /** Descriptor ring */ + union { + /** Transmit descriptors */ + union { + /** In-order transmit descriptors */ + struct gve_gqi_tx_descriptor *gqi; + /** Out-of-order transmit descriptors */ + struct gve_dqo_tx_descriptor *dqo; + } tx; + /** Receive descriptors */ + union { + /** In-order receive descriptors */ + struct gve_gqi_rx_descriptor *gqi; + /** Out-of-order receive descriptors */ + struct gve_dqo_rx_descriptor *dqo; + } rx; + /** Raw data */ + void *raw; + } desc; + /** Completion ring */ + union { + /** Transmit completions */ + union { + /** Out-of-order transmit completions */ + struct gve_dqo_tx_completion *dqo; + } tx; + /** Receive completions */ + union { + /** In-order receive completions */ + struct gve_gqi_rx_completion *gqi; + /** Out-of-order receive completions */ + struct gve_dqo_rx_completion *dqo; + } rx; + /** Raw data */ + void *raw; + } cmplt; + /** Queue resources */ + struct gve_resources *res; + + /** Queue type */ + const struct gve_queue_type *type; + /** Queue strides */ + struct gve_queue_stride stride; + /** Number of descriptors (must be a power of two) */ + unsigned int count; + /** Maximum fill level (must be a power of two) */ + unsigned int fill; + + /** Descriptor mapping */ + struct dma_mapping desc_map; + /** Completion mapping */ + struct dma_mapping cmplt_map; + /** Queue resources mapping */ + struct dma_mapping res_map; + + /** Doorbell register */ + volatile uint32_t *db; + /** Event counter */ + struct gve_event *event; + + /** Producer counter */ + uint32_t prod; + /** Consumer counter */ + uint32_t cons; + /** Completion counter */ + uint32_t done; + /** Tag ring */ + uint8_t *tag; + + /** Queue page list */ + struct gve_qpl qpl; +}; + +/** A descriptor queue type */ +struct gve_queue_type { + /** Name */ + const char *name; + /** + * Populate command parameters to create queue + * + * @v queue Descriptor queue + * @v qpl Queue page list ID + * @v cmd Admin queue command + */ + void ( * param ) ( struct gve_queue *queue, uint32_t qpl, + union gve_admin_command *cmd ); + /** Queue page list ID */ + uint32_t qpl; + /** Interrupt channel */ + uint8_t irq; + /** Maximum fill level */ + uint8_t fill; + /** Queue strides */ + struct { + /** In-order queue strides */ + struct gve_queue_stride gqi; + /** Out-of-order queue strides */ + struct gve_queue_stride dqo; + } stride; + /** Command to create queue */ + uint8_t create; + /** Command to destroy queue */ + uint8_t destroy; +}; + +/** A Google Virtual Ethernet NIC */ +struct gve_nic { + /** Configuration registers */ + void *cfg; + /** Doorbell registers */ + void *db; + /** PCI revision */ + uint8_t revision; + /** Network device */ + struct net_device *netdev; + /** DMA device */ + struct dma_device *dma; + /** Dummy MSI-X interrupt */ + struct pci_msix msix; + + /** Admin queue */ + struct gve_admin admin; + /** Interrupt channels */ + struct gve_irqs irqs; + /** Event counters */ + struct gve_events events; + /** Scratch buffer */ + struct gve_scratch scratch; + /** Supported options */ + uint32_t options; + /** Operating mode */ + unsigned int mode; + + /** Transmit queue */ + struct gve_queue tx; + /** Receive queue */ + struct gve_queue rx; + /** Transmit I/O buffers (indexed by tag) */ + struct io_buffer *tx_iobuf[GVE_TX_FILL]; + /** Transmit tag chain */ + uint8_t tx_chain[GVE_TX_FILL]; + /** Transmit tag ring */ + uint8_t tx_tag[GVE_TX_FILL]; + /** Receive tag ring */ + uint8_t rx_tag[GVE_RX_FILL]; + /** Receive sequence number */ + unsigned int seq; + + /** Startup process */ + struct process startup; + /** Startup process retry counter */ + unsigned int retries; + /** Reset recovery watchdog timer */ + struct retry_timer watchdog; + /** Reset recovery recorded activity counter */ + uint32_t activity; +}; + +/** Operating mode + * + * These values are chosen to allow for easy transformation to a queue + * format identifier as used for the "Configure device resources" + * command. + */ +#define GVE_MODE_QPL 0x01 /**< Use registered queue pages */ +#define GVE_MODE_DQO 0x02 /**< Use out-of-order queues */ + +/** Maximum time to wait for admin queue commands */ +#define GVE_ADMIN_MAX_WAIT_MS 500 + +/** Maximum number of times to reattempt device reset */ +#define GVE_RESET_MAX_RETRY 5 + +/** Time between reset recovery checks */ +#define GVE_WATCHDOG_TIMEOUT ( 1 * TICKS_PER_SEC ) + +#endif /* _GVE_H */ |
