Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,29 @@
#
# Google network device configuration
#
config NET_VENDOR_GOOGLE
bool "Google Devices"
default y
help
If you have a network (Ethernet) device belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about Google devices. If you say Y, you will be asked
for your specific device in the following questions.
if NET_VENDOR_GOOGLE
config GVE
tristate "Google Virtual NIC (gVNIC) support"
depends on (PCI_MSI && (X86 || CPU_LITTLE_ENDIAN))
depends on PTP_1588_CLOCK_OPTIONAL
select PAGE_POOL
help
This driver supports Google Virtual NIC (gVNIC)"
To compile this driver as a module, choose M here.
The module will be called gve.
endif #NET_VENDOR_GOOGLE
@@ -0,0 +1,5 @@
#
# Makefile for the Google network device drivers.
#
obj-$(CONFIG_GVE) += gve/
@@ -0,0 +1,7 @@
# Makefile for the Google virtual Ethernet (gve) driver
obj-$(CONFIG_GVE) += gve.o
gve-y := gve_main.o gve_tx.o gve_tx_dqo.o gve_rx.o gve_rx_dqo.o gve_ethtool.o gve_adminq.o gve_utils.o gve_flow_rule.o \
gve_buffer_mgmt_dqo.o
gve-$(CONFIG_PTP_1588_CLOCK) += gve_ptp.o
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,660 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
#ifndef _GVE_ADMINQ_H
#define _GVE_ADMINQ_H
#include <linux/build_bug.h>
/* Admin queue opcodes */
enum gve_adminq_opcodes {
GVE_ADMINQ_DESCRIBE_DEVICE = 0x1,
GVE_ADMINQ_CONFIGURE_DEVICE_RESOURCES = 0x2,
GVE_ADMINQ_REGISTER_PAGE_LIST = 0x3,
GVE_ADMINQ_UNREGISTER_PAGE_LIST = 0x4,
GVE_ADMINQ_CREATE_TX_QUEUE = 0x5,
GVE_ADMINQ_CREATE_RX_QUEUE = 0x6,
GVE_ADMINQ_DESTROY_TX_QUEUE = 0x7,
GVE_ADMINQ_DESTROY_RX_QUEUE = 0x8,
GVE_ADMINQ_DECONFIGURE_DEVICE_RESOURCES = 0x9,
GVE_ADMINQ_CONFIGURE_RSS = 0xA,
GVE_ADMINQ_SET_DRIVER_PARAMETER = 0xB,
GVE_ADMINQ_REPORT_STATS = 0xC,
GVE_ADMINQ_REPORT_LINK_SPEED = 0xD,
GVE_ADMINQ_GET_PTYPE_MAP = 0xE,
GVE_ADMINQ_VERIFY_DRIVER_COMPATIBILITY = 0xF,
GVE_ADMINQ_QUERY_FLOW_RULES = 0x10,
GVE_ADMINQ_REPORT_NIC_TIMESTAMP = 0x11,
GVE_ADMINQ_QUERY_RSS = 0x12,
/* For commands that are larger than 56 bytes */
GVE_ADMINQ_EXTENDED_COMMAND = 0xFF,
};
/* The normal adminq command is restricted to be 56 bytes at maximum. For the
* longer adminq command, it is wrapped by GVE_ADMINQ_EXTENDED_COMMAND with
* inner opcode of gve_adminq_extended_cmd_opcodes specified. The inner command
* is written in the dma memory allocated by GVE_ADMINQ_EXTENDED_COMMAND.
*/
enum gve_adminq_extended_cmd_opcodes {
GVE_ADMINQ_CONFIGURE_FLOW_RULE = 0x101,
};
/* Admin queue status codes */
enum gve_adminq_statuses {
GVE_ADMINQ_COMMAND_UNSET = 0x0,
GVE_ADMINQ_COMMAND_PASSED = 0x1,
GVE_ADMINQ_COMMAND_ERROR_ABORTED = 0xFFFFFFF0,
GVE_ADMINQ_COMMAND_ERROR_ALREADY_EXISTS = 0xFFFFFFF1,
GVE_ADMINQ_COMMAND_ERROR_CANCELLED = 0xFFFFFFF2,
GVE_ADMINQ_COMMAND_ERROR_DATALOSS = 0xFFFFFFF3,
GVE_ADMINQ_COMMAND_ERROR_DEADLINE_EXCEEDED = 0xFFFFFFF4,
GVE_ADMINQ_COMMAND_ERROR_FAILED_PRECONDITION = 0xFFFFFFF5,
GVE_ADMINQ_COMMAND_ERROR_INTERNAL_ERROR = 0xFFFFFFF6,
GVE_ADMINQ_COMMAND_ERROR_INVALID_ARGUMENT = 0xFFFFFFF7,
GVE_ADMINQ_COMMAND_ERROR_NOT_FOUND = 0xFFFFFFF8,
GVE_ADMINQ_COMMAND_ERROR_OUT_OF_RANGE = 0xFFFFFFF9,
GVE_ADMINQ_COMMAND_ERROR_PERMISSION_DENIED = 0xFFFFFFFA,
GVE_ADMINQ_COMMAND_ERROR_UNAUTHENTICATED = 0xFFFFFFFB,
GVE_ADMINQ_COMMAND_ERROR_RESOURCE_EXHAUSTED = 0xFFFFFFFC,
GVE_ADMINQ_COMMAND_ERROR_UNAVAILABLE = 0xFFFFFFFD,
GVE_ADMINQ_COMMAND_ERROR_UNIMPLEMENTED = 0xFFFFFFFE,
GVE_ADMINQ_COMMAND_ERROR_UNKNOWN_ERROR = 0xFFFFFFFF,
};
#define GVE_ADMINQ_DEVICE_DESCRIPTOR_VERSION 1
/* All AdminQ command structs should be naturally packed. The static_assert
* calls make sure this is the case at compile time.
*/
struct gve_adminq_describe_device {
__be64 device_descriptor_addr;
__be32 device_descriptor_version;
__be32 available_length;
};
static_assert(sizeof(struct gve_adminq_describe_device) == 16);
struct gve_device_descriptor {
__be64 max_registered_pages;
__be16 reserved1;
__be16 tx_queue_entries;
__be16 rx_queue_entries;
__be16 default_num_queues;
__be16 mtu;
__be16 counters;
__be16 tx_pages_per_qpl;
__be16 rx_pages_per_qpl;
u8 mac[ETH_ALEN];
__be16 num_device_options;
__be16 total_length;
u8 reserved2[6];
};
static_assert(sizeof(struct gve_device_descriptor) == 40);
struct gve_device_option {
__be16 option_id;
__be16 option_length;
__be32 required_features_mask;
};
static_assert(sizeof(struct gve_device_option) == 8);
struct gve_device_option_gqi_rda {
__be32 supported_features_mask;
};
static_assert(sizeof(struct gve_device_option_gqi_rda) == 4);
struct gve_device_option_gqi_qpl {
__be32 supported_features_mask;
};
static_assert(sizeof(struct gve_device_option_gqi_qpl) == 4);
struct gve_device_option_dqo_rda {
__be32 supported_features_mask;
__be32 reserved;
};
static_assert(sizeof(struct gve_device_option_dqo_rda) == 8);
struct gve_device_option_dqo_qpl {
__be32 supported_features_mask;
__be16 tx_pages_per_qpl;
__be16 rx_pages_per_qpl;
};
static_assert(sizeof(struct gve_device_option_dqo_qpl) == 8);
struct gve_device_option_jumbo_frames {
__be32 supported_features_mask;
__be16 max_mtu;
u8 padding[2];
};
static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
struct gve_device_option_buffer_sizes {
/* GVE_SUP_BUFFER_SIZES_MASK bit should be set */
__be32 supported_features_mask;
__be16 packet_buffer_size;
__be16 header_buffer_size;
};
static_assert(sizeof(struct gve_device_option_buffer_sizes) == 8);
struct gve_device_option_modify_ring {
__be32 supported_featured_mask;
__be16 max_rx_ring_size;
__be16 max_tx_ring_size;
__be16 min_rx_ring_size;
__be16 min_tx_ring_size;
};
static_assert(sizeof(struct gve_device_option_modify_ring) == 12);
struct gve_device_option_flow_steering {
__be32 supported_features_mask;
__be32 reserved;
__be32 max_flow_rules;
};
static_assert(sizeof(struct gve_device_option_flow_steering) == 12);
struct gve_device_option_rss_config {
__be32 supported_features_mask;
__be16 hash_key_size;
__be16 hash_lut_size;
};
static_assert(sizeof(struct gve_device_option_rss_config) == 8);
struct gve_device_option_nic_timestamp {
__be32 supported_features_mask;
};
static_assert(sizeof(struct gve_device_option_nic_timestamp) == 4);
/* Terminology:
*
* RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
* mapped and read/updated by the device.
*
* QPL - Queue Page Lists - Driver uses bounce buffers which are DMA mapped with
* the device for read/write and data is copied from/to SKBs.
*/
enum gve_dev_opt_id {
GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
GVE_DEV_OPT_ID_GQI_RDA = 0x2,
GVE_DEV_OPT_ID_GQI_QPL = 0x3,
GVE_DEV_OPT_ID_DQO_RDA = 0x4,
GVE_DEV_OPT_ID_MODIFY_RING = 0x6,
GVE_DEV_OPT_ID_DQO_QPL = 0x7,
GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
GVE_DEV_OPT_ID_BUFFER_SIZES = 0xa,
GVE_DEV_OPT_ID_FLOW_STEERING = 0xb,
GVE_DEV_OPT_ID_NIC_TIMESTAMP = 0xd,
GVE_DEV_OPT_ID_RSS_CONFIG = 0xe,
};
enum gve_dev_opt_req_feat_mask {
GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_DQO_QPL = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_BUFFER_SIZES = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_FLOW_STEERING = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_RSS_CONFIG = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_NIC_TIMESTAMP = 0x0,
};
enum gve_sup_feature_mask {
GVE_SUP_MODIFY_RING_MASK = 1 << 0,
GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
GVE_SUP_BUFFER_SIZES_MASK = 1 << 4,
GVE_SUP_FLOW_STEERING_MASK = 1 << 5,
GVE_SUP_RSS_CONFIG_MASK = 1 << 7,
GVE_SUP_NIC_TIMESTAMP_MASK = 1 << 8,
};
#define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0
#define GVE_VERSION_STR_LEN 128
enum gve_driver_capbility {
gve_driver_capability_gqi_qpl = 0,
gve_driver_capability_gqi_rda = 1,
gve_driver_capability_dqo_qpl = 2, /* reserved for future use */
gve_driver_capability_dqo_rda = 3,
gve_driver_capability_alt_miss_compl = 4,
gve_driver_capability_flexible_buffer_size = 5,
gve_driver_capability_flexible_rss_size = 6,
};
#define GVE_CAP1(a) BIT((int)a)
#define GVE_CAP2(a) BIT(((int)a) - 64)
#define GVE_CAP3(a) BIT(((int)a) - 128)
#define GVE_CAP4(a) BIT(((int)a) - 192)
#define GVE_DRIVER_CAPABILITY_FLAGS1 \
(GVE_CAP1(gve_driver_capability_gqi_qpl) | \
GVE_CAP1(gve_driver_capability_gqi_rda) | \
GVE_CAP1(gve_driver_capability_dqo_rda) | \
GVE_CAP1(gve_driver_capability_alt_miss_compl) | \
GVE_CAP1(gve_driver_capability_flexible_buffer_size) | \
GVE_CAP1(gve_driver_capability_flexible_rss_size))
#define GVE_DRIVER_CAPABILITY_FLAGS2 0x0
#define GVE_DRIVER_CAPABILITY_FLAGS3 0x0
#define GVE_DRIVER_CAPABILITY_FLAGS4 0x0
struct gve_adminq_extended_command {
__be32 inner_opcode;
__be32 inner_length;
__be64 inner_command_addr;
};
static_assert(sizeof(struct gve_adminq_extended_command) == 16);
struct gve_driver_info {
u8 os_type; /* 0x01 = Linux */
u8 driver_major;
u8 driver_minor;
u8 driver_sub;
__be32 os_version_major;
__be32 os_version_minor;
__be32 os_version_sub;
__be64 driver_capability_flags[4];
u8 os_version_str1[GVE_VERSION_STR_LEN];
u8 os_version_str2[GVE_VERSION_STR_LEN];
};
struct gve_adminq_verify_driver_compatibility {
__be64 driver_info_len;
__be64 driver_info_addr;
};
static_assert(sizeof(struct gve_adminq_verify_driver_compatibility) == 16);
struct gve_adminq_configure_device_resources {
__be64 counter_array;
__be64 irq_db_addr;
__be32 num_counters;
__be32 num_irq_dbs;
__be32 irq_db_stride;
__be32 ntfy_blk_msix_base_idx;
u8 queue_format;
u8 padding[7];
};
static_assert(sizeof(struct gve_adminq_configure_device_resources) == 40);
struct gve_adminq_register_page_list {
__be32 page_list_id;
__be32 num_pages;
__be64 page_address_list_addr;
__be64 page_size;
};
static_assert(sizeof(struct gve_adminq_register_page_list) == 24);
struct gve_adminq_unregister_page_list {
__be32 page_list_id;
};
static_assert(sizeof(struct gve_adminq_unregister_page_list) == 4);
#define GVE_RAW_ADDRESSING_QPL_ID 0xFFFFFFFF
struct gve_adminq_create_tx_queue {
__be32 queue_id;
__be32 reserved;
__be64 queue_resources_addr;
__be64 tx_ring_addr;
__be32 queue_page_list_id;
__be32 ntfy_id;
__be64 tx_comp_ring_addr;
__be16 tx_ring_size;
__be16 tx_comp_ring_size;
u8 padding[4];
};
static_assert(sizeof(struct gve_adminq_create_tx_queue) == 48);
struct gve_adminq_create_rx_queue {
__be32 queue_id;
__be32 index;
__be32 reserved;
__be32 ntfy_id;
__be64 queue_resources_addr;
__be64 rx_desc_ring_addr;
__be64 rx_data_ring_addr;
__be32 queue_page_list_id;
__be16 rx_ring_size;
__be16 packet_buffer_size;
__be16 rx_buff_ring_size;
u8 enable_rsc;
u8 padding1;
__be16 header_buffer_size;
u8 padding2[2];
};
static_assert(sizeof(struct gve_adminq_create_rx_queue) == 56);
/* Queue resources that are shared with the device */
struct gve_queue_resources {
union {
struct {
__be32 db_index; /* Device -> Guest */
__be32 counter_index; /* Device -> Guest */
};
u8 reserved[64];
};
};
static_assert(sizeof(struct gve_queue_resources) == 64);
struct gve_adminq_destroy_tx_queue {
__be32 queue_id;
};
static_assert(sizeof(struct gve_adminq_destroy_tx_queue) == 4);
struct gve_adminq_destroy_rx_queue {
__be32 queue_id;
};
static_assert(sizeof(struct gve_adminq_destroy_rx_queue) == 4);
/* GVE Set Driver Parameter Types */
enum gve_set_driver_param_types {
GVE_SET_PARAM_MTU = 0x1,
};
struct gve_adminq_set_driver_parameter {
__be32 parameter_type;
u8 reserved[4];
__be64 parameter_value;
};
static_assert(sizeof(struct gve_adminq_set_driver_parameter) == 16);
struct gve_adminq_report_stats {
__be64 stats_report_len;
__be64 stats_report_addr;
__be64 interval;
};
static_assert(sizeof(struct gve_adminq_report_stats) == 24);
struct gve_adminq_report_link_speed {
__be64 link_speed_address;
};
static_assert(sizeof(struct gve_adminq_report_link_speed) == 8);
struct gve_adminq_report_nic_ts {
__be64 nic_ts_report_len;
__be64 nic_ts_report_addr;
};
static_assert(sizeof(struct gve_adminq_report_nic_ts) == 16);
struct gve_nic_ts_report {
__be64 nic_timestamp; /* NIC clock in nanoseconds */
__be64 reserved1;
__be64 reserved2;
__be64 reserved3;
__be64 reserved4;
};
struct stats {
__be32 stat_name;
__be32 queue_id;
__be64 value;
};
static_assert(sizeof(struct stats) == 16);
struct gve_stats_report {
__be64 written_count;
struct stats stats[];
};
static_assert(sizeof(struct gve_stats_report) == 8);
enum gve_stat_names {
// stats from gve
TX_WAKE_CNT = 1,
TX_STOP_CNT = 2,
TX_FRAMES_SENT = 3,
TX_BYTES_SENT = 4,
TX_LAST_COMPLETION_PROCESSED = 5,
RX_NEXT_EXPECTED_SEQUENCE = 6,
RX_BUFFERS_POSTED = 7,
TX_TIMEOUT_CNT = 8,
// stats from NIC
RX_QUEUE_DROP_CNT = 65,
RX_NO_BUFFERS_POSTED = 66,
RX_DROPS_PACKET_OVER_MRU = 67,
RX_DROPS_INVALID_CHECKSUM = 68,
};
enum gve_l3_type {
/* Must be zero so zero initialized LUT is unknown. */
GVE_L3_TYPE_UNKNOWN = 0,
GVE_L3_TYPE_OTHER,
GVE_L3_TYPE_IPV4,
GVE_L3_TYPE_IPV6,
};
enum gve_l4_type {
/* Must be zero so zero initialized LUT is unknown. */
GVE_L4_TYPE_UNKNOWN = 0,
GVE_L4_TYPE_OTHER,
GVE_L4_TYPE_TCP,
GVE_L4_TYPE_UDP,
GVE_L4_TYPE_ICMP,
GVE_L4_TYPE_SCTP,
};
/* These are control path types for PTYPE which are the same as the data path
* types.
*/
struct gve_ptype_entry {
u8 l3_type;
u8 l4_type;
};
struct gve_ptype_map {
struct gve_ptype_entry ptypes[GVE_NUM_PTYPES]; /* PTYPES are always 10 bits. */
};
struct gve_adminq_get_ptype_map {
__be64 ptype_map_len;
__be64 ptype_map_addr;
};
/* Flow-steering related definitions */
enum gve_adminq_flow_rule_cfg_opcode {
GVE_FLOW_RULE_CFG_ADD = 0,
GVE_FLOW_RULE_CFG_DEL = 1,
GVE_FLOW_RULE_CFG_RESET = 2,
};
enum gve_adminq_flow_rule_query_opcode {
GVE_FLOW_RULE_QUERY_RULES = 0,
GVE_FLOW_RULE_QUERY_IDS = 1,
GVE_FLOW_RULE_QUERY_STATS = 2,
};
enum gve_adminq_flow_type {
GVE_FLOW_TYPE_TCPV4,
GVE_FLOW_TYPE_UDPV4,
GVE_FLOW_TYPE_SCTPV4,
GVE_FLOW_TYPE_AHV4,
GVE_FLOW_TYPE_ESPV4,
GVE_FLOW_TYPE_TCPV6,
GVE_FLOW_TYPE_UDPV6,
GVE_FLOW_TYPE_SCTPV6,
GVE_FLOW_TYPE_AHV6,
GVE_FLOW_TYPE_ESPV6,
};
/* Flow-steering command */
struct gve_adminq_flow_rule {
__be16 flow_type;
__be16 action; /* RX queue id */
struct gve_flow_spec key;
struct gve_flow_spec mask;
};
struct gve_adminq_configure_flow_rule {
__be16 opcode;
u8 padding[2];
struct gve_adminq_flow_rule rule;
__be32 location;
};
static_assert(sizeof(struct gve_adminq_configure_flow_rule) == 92);
struct gve_query_flow_rules_descriptor {
__be32 num_flow_rules;
__be32 max_flow_rules;
__be32 num_queried_rules;
__be32 total_length;
};
struct gve_adminq_queried_flow_rule {
__be32 location;
struct gve_adminq_flow_rule flow_rule;
};
struct gve_adminq_query_flow_rules {
__be16 opcode;
u8 padding[2];
__be32 starting_rule_id;
__be64 available_length; /* The dma memory length that the driver allocated */
__be64 rule_descriptor_addr; /* The dma memory address */
};
static_assert(sizeof(struct gve_adminq_query_flow_rules) == 24);
enum gve_rss_hash_type {
GVE_RSS_HASH_IPV4,
GVE_RSS_HASH_TCPV4,
GVE_RSS_HASH_IPV6,
GVE_RSS_HASH_IPV6_EX,
GVE_RSS_HASH_TCPV6,
GVE_RSS_HASH_TCPV6_EX,
GVE_RSS_HASH_UDPV4,
GVE_RSS_HASH_UDPV6,
GVE_RSS_HASH_UDPV6_EX,
};
struct gve_adminq_configure_rss {
__be16 hash_types;
u8 hash_alg;
u8 reserved;
__be16 hash_key_size;
__be16 hash_lut_size;
__be64 hash_key_addr;
__be64 hash_lut_addr;
};
static_assert(sizeof(struct gve_adminq_configure_rss) == 24);
struct gve_query_rss_descriptor {
__be32 total_length;
__be16 hash_types;
u8 hash_alg;
u8 reserved;
};
struct gve_adminq_query_rss {
__be64 available_length;
__be64 rss_descriptor_addr;
};
static_assert(sizeof(struct gve_adminq_query_rss) == 16);
union gve_adminq_command {
struct {
__be32 opcode;
__be32 status;
union {
struct gve_adminq_configure_device_resources
configure_device_resources;
struct gve_adminq_create_tx_queue create_tx_queue;
struct gve_adminq_create_rx_queue create_rx_queue;
struct gve_adminq_destroy_tx_queue destroy_tx_queue;
struct gve_adminq_destroy_rx_queue destroy_rx_queue;
struct gve_adminq_describe_device describe_device;
struct gve_adminq_register_page_list reg_page_list;
struct gve_adminq_unregister_page_list unreg_page_list;
struct gve_adminq_set_driver_parameter set_driver_param;
struct gve_adminq_report_stats report_stats;
struct gve_adminq_report_link_speed report_link_speed;
struct gve_adminq_get_ptype_map get_ptype_map;
struct gve_adminq_verify_driver_compatibility
verify_driver_compatibility;
struct gve_adminq_query_flow_rules query_flow_rules;
struct gve_adminq_configure_rss configure_rss;
struct gve_adminq_query_rss query_rss;
struct gve_adminq_report_nic_ts report_nic_ts;
struct gve_adminq_extended_command extended_command;
};
};
u8 reserved[64];
};
static_assert(sizeof(union gve_adminq_command) == 64);
int gve_adminq_alloc(struct device *dev, struct gve_priv *priv);
void gve_adminq_free(struct device *dev, struct gve_priv *priv);
void gve_adminq_release(struct gve_priv *priv);
int gve_adminq_describe_device(struct gve_priv *priv);
int gve_adminq_configure_device_resources(struct gve_priv *priv,
dma_addr_t counter_array_bus_addr,
u32 num_counters,
dma_addr_t db_array_bus_addr,
u32 num_ntfy_blks);
int gve_adminq_deconfigure_device_resources(struct gve_priv *priv);
int gve_adminq_create_tx_queues(struct gve_priv *priv, u32 start_id, u32 num_queues);
int gve_adminq_destroy_tx_queues(struct gve_priv *priv, u32 start_id, u32 num_queues);
int gve_adminq_create_single_rx_queue(struct gve_priv *priv, u32 queue_index);
int gve_adminq_create_rx_queues(struct gve_priv *priv, u32 num_queues);
int gve_adminq_destroy_single_rx_queue(struct gve_priv *priv, u32 queue_index);
int gve_adminq_destroy_rx_queues(struct gve_priv *priv, u32 queue_id);
int gve_adminq_register_page_list(struct gve_priv *priv,
struct gve_queue_page_list *qpl);
int gve_adminq_unregister_page_list(struct gve_priv *priv, u32 page_list_id);
int gve_adminq_report_stats(struct gve_priv *priv, u64 stats_report_len,
dma_addr_t stats_report_addr, u64 interval);
int gve_adminq_verify_driver_compatibility(struct gve_priv *priv,
u64 driver_info_len,
dma_addr_t driver_info_addr);
int gve_adminq_report_link_speed(struct gve_priv *priv);
int gve_adminq_add_flow_rule(struct gve_priv *priv, struct gve_adminq_flow_rule *rule, u32 loc);
int gve_adminq_del_flow_rule(struct gve_priv *priv, u32 loc);
int gve_adminq_reset_flow_rules(struct gve_priv *priv);
int gve_adminq_query_flow_rules(struct gve_priv *priv, u16 query_opcode, u32 starting_loc);
int gve_adminq_configure_rss(struct gve_priv *priv, struct ethtool_rxfh_param *rxfh);
int gve_adminq_query_rss_config(struct gve_priv *priv, struct ethtool_rxfh_param *rxfh);
int gve_adminq_report_nic_ts(struct gve_priv *priv,
dma_addr_t nic_ts_report_addr);
struct gve_ptype_lut;
int gve_adminq_get_ptype_map_dqo(struct gve_priv *priv,
struct gve_ptype_lut *ptype_lut);
#endif /* _GVE_ADMINQ_H */
@@ -0,0 +1,344 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2024 Google, Inc.
*/
#include <net/xdp_sock_drv.h>
#include "gve.h"
#include "gve_utils.h"
int gve_buf_ref_cnt(struct gve_rx_buf_state_dqo *bs)
{
return page_count(bs->page_info.page) - bs->page_info.pagecnt_bias;
}
struct gve_rx_buf_state_dqo *gve_alloc_buf_state(struct gve_rx_ring *rx)
{
struct gve_rx_buf_state_dqo *buf_state;
s16 buffer_id;
buffer_id = rx->dqo.free_buf_states;
if (unlikely(buffer_id == -1))
return NULL;
buf_state = &rx->dqo.buf_states[buffer_id];
/* Remove buf_state from free list */
rx->dqo.free_buf_states = buf_state->next;
/* Point buf_state to itself to mark it as allocated */
buf_state->next = buffer_id;
/* Clear the buffer pointers */
buf_state->page_info.page = NULL;
buf_state->xsk_buff = NULL;
return buf_state;
}
bool gve_buf_state_is_allocated(struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state)
{
s16 buffer_id = buf_state - rx->dqo.buf_states;
return buf_state->next == buffer_id;
}
void gve_free_buf_state(struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state)
{
s16 buffer_id = buf_state - rx->dqo.buf_states;
buf_state->next = rx->dqo.free_buf_states;
rx->dqo.free_buf_states = buffer_id;
}
struct gve_rx_buf_state_dqo *gve_dequeue_buf_state(struct gve_rx_ring *rx,
struct gve_index_list *list)
{
struct gve_rx_buf_state_dqo *buf_state;
s16 buffer_id;
buffer_id = list->head;
if (unlikely(buffer_id == -1))
return NULL;
buf_state = &rx->dqo.buf_states[buffer_id];
/* Remove buf_state from list */
list->head = buf_state->next;
if (buf_state->next == -1)
list->tail = -1;
/* Point buf_state to itself to mark it as allocated */
buf_state->next = buffer_id;
return buf_state;
}
void gve_enqueue_buf_state(struct gve_rx_ring *rx, struct gve_index_list *list,
struct gve_rx_buf_state_dqo *buf_state)
{
s16 buffer_id = buf_state - rx->dqo.buf_states;
buf_state->next = -1;
if (list->head == -1) {
list->head = buffer_id;
list->tail = buffer_id;
} else {
int tail = list->tail;
rx->dqo.buf_states[tail].next = buffer_id;
list->tail = buffer_id;
}
}
struct gve_rx_buf_state_dqo *gve_get_recycled_buf_state(struct gve_rx_ring *rx)
{
struct gve_rx_buf_state_dqo *buf_state;
int i;
/* Recycled buf states are immediately usable. */
buf_state = gve_dequeue_buf_state(rx, &rx->dqo.recycled_buf_states);
if (likely(buf_state))
return buf_state;
if (unlikely(rx->dqo.used_buf_states.head == -1))
return NULL;
/* Used buf states are only usable when ref count reaches 0, which means
* no SKBs refer to them.
*
* Search a limited number before giving up.
*/
for (i = 0; i < 5; i++) {
buf_state = gve_dequeue_buf_state(rx, &rx->dqo.used_buf_states);
if (gve_buf_ref_cnt(buf_state) == 0) {
rx->dqo.used_buf_states_cnt--;
return buf_state;
}
gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state);
}
return NULL;
}
int gve_alloc_qpl_page_dqo(struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state)
{
struct gve_priv *priv = rx->gve;
u32 idx;
idx = rx->dqo.next_qpl_page_idx;
if (idx >= priv->rx_pages_per_qpl) {
net_err_ratelimited("%s: Out of QPL pages\n",
priv->dev->name);
return -ENOMEM;
}
buf_state->page_info.page = rx->dqo.qpl->pages[idx];
buf_state->addr = rx->dqo.qpl->page_buses[idx];
rx->dqo.next_qpl_page_idx++;
buf_state->page_info.page_offset = 0;
buf_state->page_info.page_address =
page_address(buf_state->page_info.page);
buf_state->page_info.buf_size = rx->packet_buffer_truesize;
buf_state->page_info.pad = rx->rx_headroom;
buf_state->last_single_ref_offset = 0;
/* The page already has 1 ref. */
page_ref_add(buf_state->page_info.page, INT_MAX - 1);
buf_state->page_info.pagecnt_bias = INT_MAX;
return 0;
}
void gve_free_qpl_page_dqo(struct gve_rx_buf_state_dqo *buf_state)
{
if (!buf_state->page_info.page)
return;
page_ref_sub(buf_state->page_info.page,
buf_state->page_info.pagecnt_bias - 1);
buf_state->page_info.page = NULL;
}
void gve_try_recycle_buf(struct gve_priv *priv, struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state)
{
const u16 data_buffer_size = rx->packet_buffer_truesize;
int pagecount;
/* Can't reuse if we only fit one buffer per page */
if (data_buffer_size * 2 > PAGE_SIZE)
goto mark_used;
pagecount = gve_buf_ref_cnt(buf_state);
/* Record the offset when we have a single remaining reference.
*
* When this happens, we know all of the other offsets of the page are
* usable.
*/
if (pagecount == 1) {
buf_state->last_single_ref_offset =
buf_state->page_info.page_offset;
}
/* Use the next buffer sized chunk in the page. */
buf_state->page_info.page_offset += data_buffer_size;
buf_state->page_info.page_offset &= (PAGE_SIZE - 1);
/* If we wrap around to the same offset without ever dropping to 1
* reference, then we don't know if this offset was ever freed.
*/
if (buf_state->page_info.page_offset ==
buf_state->last_single_ref_offset) {
goto mark_used;
}
gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, buf_state);
return;
mark_used:
gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state);
rx->dqo.used_buf_states_cnt++;
}
void gve_free_to_page_pool(struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state,
bool allow_direct)
{
netmem_ref netmem = buf_state->page_info.netmem;
if (!netmem)
return;
page_pool_put_full_netmem(netmem_get_pp(netmem), netmem, allow_direct);
buf_state->page_info.netmem = 0;
}
static int gve_alloc_from_page_pool(struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state)
{
netmem_ref netmem;
buf_state->page_info.buf_size = rx->packet_buffer_truesize;
netmem = page_pool_alloc_netmem(rx->dqo.page_pool,
&buf_state->page_info.page_offset,
&buf_state->page_info.buf_size,
GFP_ATOMIC);
if (!netmem)
return -ENOMEM;
buf_state->page_info.netmem = netmem;
buf_state->page_info.page_address = netmem_address(netmem);
buf_state->addr = page_pool_get_dma_addr_netmem(netmem);
buf_state->page_info.pad = rx->dqo.page_pool->p.offset;
return 0;
}
struct page_pool *gve_rx_create_page_pool(struct gve_priv *priv,
struct gve_rx_ring *rx,
bool xdp)
{
u32 ntfy_id = gve_rx_idx_to_ntfy(priv, rx->q_num);
struct page_pool_params pp = {
.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
.order = 0,
.pool_size = GVE_PAGE_POOL_SIZE_MULTIPLIER * priv->rx_desc_cnt,
.nid = priv->numa_node,
.dev = &priv->pdev->dev,
.netdev = priv->dev,
.napi = &priv->ntfy_blocks[ntfy_id].napi,
.max_len = PAGE_SIZE,
.dma_dir = xdp ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE,
.offset = xdp ? XDP_PACKET_HEADROOM : 0,
};
if (priv->header_split_enabled) {
pp.flags |= PP_FLAG_ALLOW_UNREADABLE_NETMEM;
pp.queue_idx = rx->q_num;
}
return page_pool_create(&pp);
}
void gve_free_buffer(struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state)
{
if (rx->dqo.page_pool) {
gve_free_to_page_pool(rx, buf_state, true);
gve_free_buf_state(rx, buf_state);
} else {
gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states,
buf_state);
}
}
void gve_reuse_buffer(struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state)
{
if (rx->dqo.page_pool) {
buf_state->page_info.netmem = 0;
gve_free_buf_state(rx, buf_state);
} else {
gve_dec_pagecnt_bias(&buf_state->page_info);
gve_try_recycle_buf(rx->gve, rx, buf_state);
}
}
int gve_alloc_buffer(struct gve_rx_ring *rx, struct gve_rx_desc_dqo *desc)
{
struct gve_rx_buf_state_dqo *buf_state;
if (rx->xsk_pool) {
buf_state = gve_alloc_buf_state(rx);
if (unlikely(!buf_state))
return -ENOMEM;
buf_state->xsk_buff = xsk_buff_alloc(rx->xsk_pool);
if (unlikely(!buf_state->xsk_buff)) {
xsk_set_rx_need_wakeup(rx->xsk_pool);
gve_free_buf_state(rx, buf_state);
return -ENOMEM;
}
/* Allocated xsk buffer. Clear wakeup in case it was set. */
xsk_clear_rx_need_wakeup(rx->xsk_pool);
desc->buf_id = cpu_to_le16(buf_state - rx->dqo.buf_states);
desc->buf_addr =
cpu_to_le64(xsk_buff_xdp_get_dma(buf_state->xsk_buff));
return 0;
} else if (rx->dqo.page_pool) {
buf_state = gve_alloc_buf_state(rx);
if (WARN_ON_ONCE(!buf_state))
return -ENOMEM;
if (gve_alloc_from_page_pool(rx, buf_state))
goto free_buf_state;
} else {
buf_state = gve_get_recycled_buf_state(rx);
if (unlikely(!buf_state)) {
buf_state = gve_alloc_buf_state(rx);
if (unlikely(!buf_state))
return -ENOMEM;
if (unlikely(gve_alloc_qpl_page_dqo(rx, buf_state)))
goto free_buf_state;
}
}
desc->buf_id = cpu_to_le16(buf_state - rx->dqo.buf_states);
desc->buf_addr = cpu_to_le64(buf_state->addr +
buf_state->page_info.page_offset +
buf_state->page_info.pad);
return 0;
free_buf_state:
gve_free_buf_state(rx, buf_state);
return -ENOMEM;
}
@@ -0,0 +1,139 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2019 Google, Inc.
*/
/* GVE Transmit Descriptor formats */
#ifndef _GVE_DESC_H_
#define _GVE_DESC_H_
#include <linux/build_bug.h>
/* A note on seg_addrs
*
* Base addresses encoded in seg_addr are not assumed to be physical
* addresses. The ring format assumes these come from some linear address
* space. This could be physical memory, kernel virtual memory, user virtual
* memory.
* If raw dma addressing is not supported then gVNIC uses lists of registered
* pages. Each queue is assumed to be associated with a single such linear
* address space to ensure a consistent meaning for seg_addrs posted to its
* rings.
*/
struct gve_tx_pkt_desc {
u8 type_flags; /* desc type is lower 4 bits, flags upper */
u8 l4_csum_offset; /* relative offset of L4 csum word */
u8 l4_hdr_offset; /* Offset of start of L4 headers in packet */
u8 desc_cnt; /* Total descriptors for this packet */
__be16 len; /* Total length of this packet (in bytes) */
__be16 seg_len; /* Length of this descriptor's segment */
__be64 seg_addr; /* Base address (see note) of this segment */
} __packed;
struct gve_tx_mtd_desc {
u8 type_flags; /* type is lower 4 bits, subtype upper */
u8 path_state; /* state is lower 4 bits, hash type upper */
__be16 reserved0;
__be32 path_hash;
__be64 reserved1;
} __packed;
struct gve_tx_seg_desc {
u8 type_flags; /* type is lower 4 bits, flags upper */
u8 l3_offset; /* TSO: 2 byte units to start of IPH */
__be16 reserved;
__be16 mss; /* TSO MSS */
__be16 seg_len;
__be64 seg_addr;
} __packed;
/* GVE Transmit Descriptor Types */
#define GVE_TXD_STD (0x0 << 4) /* Std with Host Address */
#define GVE_TXD_TSO (0x1 << 4) /* TSO with Host Address */
#define GVE_TXD_SEG (0x2 << 4) /* Seg with Host Address */
#define GVE_TXD_MTD (0x3 << 4) /* Metadata */
/* GVE Transmit Descriptor Flags for Std Pkts */
#define GVE_TXF_L4CSUM BIT(0) /* Need csum offload */
#define GVE_TXF_TSTAMP BIT(2) /* Timestamp required */
/* GVE Transmit Descriptor Flags for TSO Segs */
#define GVE_TXSF_IPV6 BIT(1) /* IPv6 TSO */
/* GVE Transmit Descriptor Options for MTD Segs */
#define GVE_MTD_SUBTYPE_PATH 0
#define GVE_MTD_PATH_STATE_DEFAULT 0
#define GVE_MTD_PATH_STATE_TIMEOUT 1
#define GVE_MTD_PATH_STATE_CONGESTION 2
#define GVE_MTD_PATH_STATE_RETRANSMIT 3
#define GVE_MTD_PATH_HASH_NONE (0x0 << 4)
#define GVE_MTD_PATH_HASH_L4 (0x1 << 4)
/* GVE Receive Packet Descriptor */
/* The start of an ethernet packet comes 2 bytes into the rx buffer.
* gVNIC adds this padding so that both the DMA and the L3/4 protocol header
* access is aligned.
*/
#define GVE_RX_PAD 2
struct gve_rx_desc {
u8 padding[48];
__be32 rss_hash; /* Receive-side scaling hash (Toeplitz for gVNIC) */
__be16 mss;
__be16 reserved; /* Reserved to zero */
u8 hdr_len; /* Header length (L2-L4) including padding */
u8 hdr_off; /* 64-byte-scaled offset into RX_DATA entry */
__sum16 csum; /* 1's-complement partial checksum of L3+ bytes */
__be16 len; /* Length of the received packet */
__be16 flags_seq; /* Flags [15:3] and sequence number [2:0] (1-7) */
} __packed;
static_assert(sizeof(struct gve_rx_desc) == 64);
/* If the device supports raw dma addressing then the addr in data slot is
* the dma address of the buffer.
* If the device only supports registered segments then the addr is a byte
* offset into the registered segment (an ordered list of pages) where the
* buffer is.
*/
union gve_rx_data_slot {
__be64 qpl_offset;
__be64 addr;
};
/* GVE Receive Packet Descriptor Seq No */
#define GVE_SEQNO(x) (be16_to_cpu(x) & 0x7)
/* GVE Receive Packet Descriptor Flags */
#define GVE_RXFLG(x) cpu_to_be16(1 << (3 + (x)))
#define GVE_RXF_FRAG GVE_RXFLG(3) /* IP Fragment */
#define GVE_RXF_IPV4 GVE_RXFLG(4) /* IPv4 */
#define GVE_RXF_IPV6 GVE_RXFLG(5) /* IPv6 */
#define GVE_RXF_TCP GVE_RXFLG(6) /* TCP Packet */
#define GVE_RXF_UDP GVE_RXFLG(7) /* UDP Packet */
#define GVE_RXF_ERR GVE_RXFLG(8) /* Packet Error Detected */
#define GVE_RXF_PKT_CONT GVE_RXFLG(10) /* Multi Fragment RX packet */
/* GVE IRQ */
#define GVE_IRQ_ACK BIT(31)
#define GVE_IRQ_MASK BIT(30)
#define GVE_IRQ_EVENT BIT(29)
static inline bool gve_needs_rss(__be16 flag)
{
if (flag & GVE_RXF_FRAG)
return false;
if (flag & (GVE_RXF_IPV4 | GVE_RXF_IPV6))
return true;
return false;
}
static inline u8 gve_next_seqno(u8 seq)
{
return (seq + 1) == 8 ? 1 : seq + 1;
}
#endif /* _GVE_DESC_H_ */
@@ -0,0 +1,263 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
/* GVE DQO Descriptor formats */
#ifndef _GVE_DESC_DQO_H_
#define _GVE_DESC_DQO_H_
#include <linux/build_bug.h>
#define GVE_TX_MAX_HDR_SIZE_DQO 255
#define GVE_TX_MIN_TSO_MSS_DQO 88
#ifndef __LITTLE_ENDIAN_BITFIELD
#error "Only little endian supported"
#endif
/* Basic TX descriptor (DTYPE 0x0C) */
struct gve_tx_pkt_desc_dqo {
__le64 buf_addr;
/* Must be GVE_TX_PKT_DESC_DTYPE_DQO (0xc) */
u8 dtype: 5;
/* Denotes the last descriptor of a packet. */
u8 end_of_packet: 1;
u8 checksum_offload_enable: 1;
/* If set, will generate a descriptor completion for this descriptor. */
u8 report_event: 1;
u8 reserved0;
__le16 reserved1;
/* The TX completion associated with this packet will contain this tag.
*/
__le16 compl_tag;
u16 buf_size: 14;
u16 reserved2: 2;
} __packed;
static_assert(sizeof(struct gve_tx_pkt_desc_dqo) == 16);
#define GVE_TX_PKT_DESC_DTYPE_DQO 0xc
#define GVE_TX_MAX_BUF_SIZE_DQO ((16 * 1024) - 1)
/* Maximum number of data descriptors allowed per packet, or per-TSO segment. */
#define GVE_TX_MAX_DATA_DESCS 10
/* Min gap between tail and head to avoid cacheline overlap */
#define GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP 4
/* "report_event" on TX packet descriptors may only be reported on the last
* descriptor of a TX packet, and they must be spaced apart with at least this
* value.
*/
#define GVE_TX_MIN_RE_INTERVAL 32
struct gve_tx_context_cmd_dtype {
u8 dtype: 5;
u8 tso: 1;
u8 reserved1: 2;
u8 reserved2;
};
static_assert(sizeof(struct gve_tx_context_cmd_dtype) == 2);
/* TX Native TSO Context DTYPE (0x05)
*
* "flex" fields allow the driver to send additional packet context to HW.
*/
struct gve_tx_tso_context_desc_dqo {
/* The L4 payload bytes that should be segmented. */
u32 tso_total_len: 24;
u32 flex10: 8;
/* Max segment size in TSO excluding headers. */
u16 mss: 14;
u16 reserved: 2;
u8 header_len; /* Header length to use for TSO offload */
u8 flex11;
struct gve_tx_context_cmd_dtype cmd_dtype;
u8 flex0;
u8 flex5;
u8 flex6;
u8 flex7;
u8 flex8;
u8 flex9;
} __packed;
static_assert(sizeof(struct gve_tx_tso_context_desc_dqo) == 16);
#define GVE_TX_TSO_CTX_DESC_DTYPE_DQO 0x5
/* General context descriptor for sending metadata. */
struct gve_tx_general_context_desc_dqo {
u8 flex4;
u8 flex5;
u8 flex6;
u8 flex7;
u8 flex8;
u8 flex9;
u8 flex10;
u8 flex11;
struct gve_tx_context_cmd_dtype cmd_dtype;
u16 reserved;
u8 flex0;
u8 flex1;
u8 flex2;
u8 flex3;
} __packed;
static_assert(sizeof(struct gve_tx_general_context_desc_dqo) == 16);
#define GVE_TX_GENERAL_CTX_DESC_DTYPE_DQO 0x4
/* Logical structure of metadata which is packed into context descriptor flex
* fields.
*/
struct gve_tx_metadata_dqo {
union {
struct {
u8 version;
/* If `skb->l4_hash` is set, this value should be
* derived from `skb->hash`.
*
* A zero value means no l4_hash was associated with the
* skb.
*/
u16 path_hash: 15;
/* Should be set to 1 if the flow associated with the
* skb had a rehash from the TCP stack.
*/
u16 rehash_event: 1;
} __packed;
u8 bytes[12];
};
} __packed;
static_assert(sizeof(struct gve_tx_metadata_dqo) == 12);
#define GVE_TX_METADATA_VERSION_DQO 0
/* TX completion descriptor */
struct gve_tx_compl_desc {
/* For types 0-4 this is the TX queue ID associated with this
* completion.
*/
u16 id: 11;
/* See: GVE_COMPL_TYPE_DQO* */
u16 type: 3;
u16 reserved0: 1;
/* Flipped by HW to notify the descriptor is populated. */
u16 generation: 1;
union {
/* For descriptor completions, this is the last index fetched
* by HW + 1.
*/
__le16 tx_head;
/* For packet completions, this is the completion tag set on the
* TX packet descriptors.
*/
__le16 completion_tag;
};
__le32 reserved1;
} __packed;
static_assert(sizeof(struct gve_tx_compl_desc) == 8);
#define GVE_COMPL_TYPE_DQO_PKT 0x2 /* Packet completion */
#define GVE_COMPL_TYPE_DQO_DESC 0x4 /* Descriptor completion */
#define GVE_COMPL_TYPE_DQO_MISS 0x1 /* Miss path completion */
#define GVE_COMPL_TYPE_DQO_REINJECTION 0x3 /* Re-injection completion */
/* The most significant bit in the completion tag can change the completion
* type from packet completion to miss path completion.
*/
#define GVE_ALT_MISS_COMPL_BIT BIT(15)
/* Descriptor to post buffers to HW on buffer queue. */
struct gve_rx_desc_dqo {
__le16 buf_id; /* ID returned in Rx completion descriptor */
__le16 reserved0;
__le32 reserved1;
__le64 buf_addr; /* DMA address of the buffer */
__le64 header_buf_addr;
__le64 reserved2;
} __packed;
static_assert(sizeof(struct gve_rx_desc_dqo) == 32);
/* Descriptor for HW to notify SW of new packets received on RX queue. */
struct gve_rx_compl_desc_dqo {
/* Must be 1 */
u8 rxdid: 4;
u8 reserved0: 4;
/* Packet originated from this system rather than the network. */
u8 loopback: 1;
/* Set when IPv6 packet contains a destination options header or routing
* header.
*/
u8 ipv6_ex_add: 1;
/* Invalid packet was received. */
u8 rx_error: 1;
u8 reserved1: 5;
u16 packet_type: 10;
u16 ip_hdr_err: 1;
u16 udp_len_err: 1;
u16 raw_cs_invalid: 1;
u16 reserved2: 3;
u16 packet_len: 14;
/* Flipped by HW to notify the descriptor is populated. */
u16 generation: 1;
/* Should be zero. */
u16 buffer_queue_id: 1;
u16 header_len: 10;
u16 rsc: 1;
u16 split_header: 1;
u16 reserved3: 4;
u8 descriptor_done: 1;
u8 end_of_packet: 1;
u8 header_buffer_overflow: 1;
u8 l3_l4_processed: 1;
u8 csum_ip_err: 1;
u8 csum_l4_err: 1;
u8 csum_external_ip_err: 1;
u8 csum_external_udp_err: 1;
u8 status_error1;
u8 reserved5;
u8 ts_sub_nsecs_low;
__le16 buf_id; /* Buffer ID which was sent on the buffer queue. */
union {
/* Packet checksum. */
__le16 raw_cs;
/* Segment length for RSC packets. */
__le16 rsc_seg_len;
};
__le32 hash;
__le32 reserved6;
__le32 reserved7;
__le32 ts; /* timestamp in nanosecs */
} __packed;
static_assert(sizeof(struct gve_rx_compl_desc_dqo) == 32);
/* Ringing the doorbell too often can hurt performance.
*
* HW requires this value to be at least 8.
*/
#define GVE_RX_BUF_THRESH_DQO 32
#endif /* _GVE_DESC_DQO_H_ */
@@ -0,0 +1,116 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
#ifndef _GVE_DQO_H_
#define _GVE_DQO_H_
#include "gve_adminq.h"
#define GVE_ITR_ENABLE_BIT_DQO BIT(0)
#define GVE_ITR_CLEAR_PBA_BIT_DQO BIT(1)
#define GVE_ITR_NO_UPDATE_DQO (3 << 3)
#define GVE_ITR_INTERVAL_DQO_SHIFT 5
#define GVE_ITR_INTERVAL_DQO_MASK ((1 << 12) - 1)
#define GVE_TX_IRQ_RATELIMIT_US_DQO 50
#define GVE_RX_IRQ_RATELIMIT_US_DQO 20
#define GVE_MAX_ITR_INTERVAL_DQO (GVE_ITR_INTERVAL_DQO_MASK * 2)
/* Timeout in seconds to wait for a reinjection completion after receiving
* its corresponding miss completion.
*/
#define GVE_REINJECT_COMPL_TIMEOUT 1
/* Timeout in seconds to deallocate the completion tag for a packet that was
* prematurely freed for not receiving a valid completion. This should be large
* enough to rule out the possibility of receiving the corresponding valid
* completion after this interval.
*/
#define GVE_DEALLOCATE_COMPL_TIMEOUT 60
netdev_tx_t gve_tx_dqo(struct sk_buff *skb, struct net_device *dev);
netdev_features_t gve_features_check_dqo(struct sk_buff *skb,
struct net_device *dev,
netdev_features_t features);
int gve_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp);
bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean);
bool gve_xdp_poll_dqo(struct gve_notify_block *block);
bool gve_xsk_tx_poll_dqo(struct gve_notify_block *block, int budget);
int gve_rx_poll_dqo(struct gve_notify_block *block, int budget);
int gve_tx_alloc_rings_dqo(struct gve_priv *priv,
struct gve_tx_alloc_rings_cfg *cfg);
void gve_tx_free_rings_dqo(struct gve_priv *priv,
struct gve_tx_alloc_rings_cfg *cfg);
void gve_tx_start_ring_dqo(struct gve_priv *priv, int idx);
void gve_tx_stop_ring_dqo(struct gve_priv *priv, int idx);
int gve_rx_alloc_ring_dqo(struct gve_priv *priv,
struct gve_rx_alloc_rings_cfg *cfg,
struct gve_rx_ring *rx,
int idx);
void gve_rx_free_ring_dqo(struct gve_priv *priv, struct gve_rx_ring *rx,
struct gve_rx_alloc_rings_cfg *cfg);
int gve_rx_alloc_rings_dqo(struct gve_priv *priv,
struct gve_rx_alloc_rings_cfg *cfg);
void gve_rx_free_rings_dqo(struct gve_priv *priv,
struct gve_rx_alloc_rings_cfg *cfg);
void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx);
void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx);
int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
struct napi_struct *napi);
void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx);
void gve_rx_write_doorbell_dqo(const struct gve_priv *priv, int queue_idx);
void gve_xdp_tx_flush_dqo(struct gve_priv *priv, u32 xdp_qid);
static inline void
gve_tx_put_doorbell_dqo(const struct gve_priv *priv,
const struct gve_queue_resources *q_resources, u32 val)
{
u64 index;
index = be32_to_cpu(q_resources->db_index);
iowrite32(val, &priv->db_bar2[index]);
}
/* Builds register value to write to DQO IRQ doorbell to enable with specified
* ITR interval.
*/
static inline u32 gve_setup_itr_interval_dqo(u32 interval_us)
{
u32 result = GVE_ITR_ENABLE_BIT_DQO;
/* Interval has 2us granularity. */
interval_us >>= 1;
interval_us &= GVE_ITR_INTERVAL_DQO_MASK;
result |= (interval_us << GVE_ITR_INTERVAL_DQO_SHIFT);
return result;
}
static inline void
gve_write_irq_doorbell_dqo(const struct gve_priv *priv,
const struct gve_notify_block *block, u32 val)
{
u32 index = be32_to_cpu(*block->irq_db_index);
iowrite32(val, &priv->db_bar2[index]);
}
/* Sets interrupt throttling interval and enables interrupt
* by writing to IRQ doorbell.
*/
static inline void
gve_set_itr_coalesce_usecs_dqo(struct gve_priv *priv,
struct gve_notify_block *block,
u32 usecs)
{
gve_write_irq_doorbell_dqo(priv, block,
gve_setup_itr_interval_dqo(usecs));
}
int gve_napi_poll_dqo(struct napi_struct *napi, int budget);
#endif /* _GVE_DQO_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,298 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2024 Google LLC
*/
#include "gve.h"
#include "gve_adminq.h"
static
int gve_fill_ethtool_flow_spec(struct ethtool_rx_flow_spec *fsp,
struct gve_adminq_queried_flow_rule *rule)
{
struct gve_adminq_flow_rule *flow_rule = &rule->flow_rule;
static const u16 flow_type_lut[] = {
[GVE_FLOW_TYPE_TCPV4] = TCP_V4_FLOW,
[GVE_FLOW_TYPE_UDPV4] = UDP_V4_FLOW,
[GVE_FLOW_TYPE_SCTPV4] = SCTP_V4_FLOW,
[GVE_FLOW_TYPE_AHV4] = AH_V4_FLOW,
[GVE_FLOW_TYPE_ESPV4] = ESP_V4_FLOW,
[GVE_FLOW_TYPE_TCPV6] = TCP_V6_FLOW,
[GVE_FLOW_TYPE_UDPV6] = UDP_V6_FLOW,
[GVE_FLOW_TYPE_SCTPV6] = SCTP_V6_FLOW,
[GVE_FLOW_TYPE_AHV6] = AH_V6_FLOW,
[GVE_FLOW_TYPE_ESPV6] = ESP_V6_FLOW,
};
if (be16_to_cpu(flow_rule->flow_type) >= ARRAY_SIZE(flow_type_lut))
return -EINVAL;
fsp->flow_type = flow_type_lut[be16_to_cpu(flow_rule->flow_type)];
memset(&fsp->h_u, 0, sizeof(fsp->h_u));
memset(&fsp->h_ext, 0, sizeof(fsp->h_ext));
memset(&fsp->m_u, 0, sizeof(fsp->m_u));
memset(&fsp->m_ext, 0, sizeof(fsp->m_ext));
switch (fsp->flow_type) {
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
fsp->h_u.tcp_ip4_spec.ip4src = flow_rule->key.src_ip[0];
fsp->h_u.tcp_ip4_spec.ip4dst = flow_rule->key.dst_ip[0];
fsp->h_u.tcp_ip4_spec.psrc = flow_rule->key.src_port;
fsp->h_u.tcp_ip4_spec.pdst = flow_rule->key.dst_port;
fsp->h_u.tcp_ip4_spec.tos = flow_rule->key.tos;
fsp->m_u.tcp_ip4_spec.ip4src = flow_rule->mask.src_ip[0];
fsp->m_u.tcp_ip4_spec.ip4dst = flow_rule->mask.dst_ip[0];
fsp->m_u.tcp_ip4_spec.psrc = flow_rule->mask.src_port;
fsp->m_u.tcp_ip4_spec.pdst = flow_rule->mask.dst_port;
fsp->m_u.tcp_ip4_spec.tos = flow_rule->mask.tos;
break;
case AH_V4_FLOW:
case ESP_V4_FLOW:
fsp->h_u.ah_ip4_spec.ip4src = flow_rule->key.src_ip[0];
fsp->h_u.ah_ip4_spec.ip4dst = flow_rule->key.dst_ip[0];
fsp->h_u.ah_ip4_spec.spi = flow_rule->key.spi;
fsp->h_u.ah_ip4_spec.tos = flow_rule->key.tos;
fsp->m_u.ah_ip4_spec.ip4src = flow_rule->mask.src_ip[0];
fsp->m_u.ah_ip4_spec.ip4dst = flow_rule->mask.dst_ip[0];
fsp->m_u.ah_ip4_spec.spi = flow_rule->mask.spi;
fsp->m_u.ah_ip4_spec.tos = flow_rule->mask.tos;
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
memcpy(fsp->h_u.tcp_ip6_spec.ip6src, &flow_rule->key.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->h_u.tcp_ip6_spec.ip6dst, &flow_rule->key.dst_ip,
sizeof(struct in6_addr));
fsp->h_u.tcp_ip6_spec.psrc = flow_rule->key.src_port;
fsp->h_u.tcp_ip6_spec.pdst = flow_rule->key.dst_port;
fsp->h_u.tcp_ip6_spec.tclass = flow_rule->key.tclass;
memcpy(fsp->m_u.tcp_ip6_spec.ip6src, &flow_rule->mask.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->m_u.tcp_ip6_spec.ip6dst, &flow_rule->mask.dst_ip,
sizeof(struct in6_addr));
fsp->m_u.tcp_ip6_spec.psrc = flow_rule->mask.src_port;
fsp->m_u.tcp_ip6_spec.pdst = flow_rule->mask.dst_port;
fsp->m_u.tcp_ip6_spec.tclass = flow_rule->mask.tclass;
break;
case AH_V6_FLOW:
case ESP_V6_FLOW:
memcpy(fsp->h_u.ah_ip6_spec.ip6src, &flow_rule->key.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->h_u.ah_ip6_spec.ip6dst, &flow_rule->key.dst_ip,
sizeof(struct in6_addr));
fsp->h_u.ah_ip6_spec.spi = flow_rule->key.spi;
fsp->h_u.ah_ip6_spec.tclass = flow_rule->key.tclass;
memcpy(fsp->m_u.ah_ip6_spec.ip6src, &flow_rule->mask.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->m_u.ah_ip6_spec.ip6dst, &flow_rule->mask.dst_ip,
sizeof(struct in6_addr));
fsp->m_u.ah_ip6_spec.spi = flow_rule->mask.spi;
fsp->m_u.ah_ip6_spec.tclass = flow_rule->mask.tclass;
break;
default:
return -EINVAL;
}
fsp->ring_cookie = be16_to_cpu(flow_rule->action);
return 0;
}
static int gve_generate_flow_rule(struct gve_priv *priv, struct ethtool_rx_flow_spec *fsp,
struct gve_adminq_flow_rule *rule)
{
static const u16 flow_type_lut[] = {
[TCP_V4_FLOW] = GVE_FLOW_TYPE_TCPV4,
[UDP_V4_FLOW] = GVE_FLOW_TYPE_UDPV4,
[SCTP_V4_FLOW] = GVE_FLOW_TYPE_SCTPV4,
[AH_V4_FLOW] = GVE_FLOW_TYPE_AHV4,
[ESP_V4_FLOW] = GVE_FLOW_TYPE_ESPV4,
[TCP_V6_FLOW] = GVE_FLOW_TYPE_TCPV6,
[UDP_V6_FLOW] = GVE_FLOW_TYPE_UDPV6,
[SCTP_V6_FLOW] = GVE_FLOW_TYPE_SCTPV6,
[AH_V6_FLOW] = GVE_FLOW_TYPE_AHV6,
[ESP_V6_FLOW] = GVE_FLOW_TYPE_ESPV6,
};
u32 flow_type;
if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
return -EOPNOTSUPP;
if (fsp->ring_cookie >= priv->rx_cfg.num_queues)
return -EINVAL;
rule->action = cpu_to_be16(fsp->ring_cookie);
flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
if (!flow_type || flow_type >= ARRAY_SIZE(flow_type_lut))
return -EINVAL;
rule->flow_type = cpu_to_be16(flow_type_lut[flow_type]);
switch (flow_type) {
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
rule->key.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
rule->key.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
rule->key.src_port = fsp->h_u.tcp_ip4_spec.psrc;
rule->key.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
rule->mask.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
rule->mask.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
rule->mask.src_port = fsp->m_u.tcp_ip4_spec.psrc;
rule->mask.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
break;
case AH_V4_FLOW:
case ESP_V4_FLOW:
rule->key.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
rule->key.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
rule->key.spi = fsp->h_u.ah_ip4_spec.spi;
rule->mask.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
rule->mask.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
rule->mask.spi = fsp->m_u.ah_ip4_spec.spi;
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
memcpy(&rule->key.src_ip, fsp->h_u.tcp_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&rule->key.dst_ip, fsp->h_u.tcp_ip6_spec.ip6dst,
sizeof(struct in6_addr));
rule->key.src_port = fsp->h_u.tcp_ip6_spec.psrc;
rule->key.dst_port = fsp->h_u.tcp_ip6_spec.pdst;
memcpy(&rule->mask.src_ip, fsp->m_u.tcp_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&rule->mask.dst_ip, fsp->m_u.tcp_ip6_spec.ip6dst,
sizeof(struct in6_addr));
rule->mask.src_port = fsp->m_u.tcp_ip6_spec.psrc;
rule->mask.dst_port = fsp->m_u.tcp_ip6_spec.pdst;
break;
case AH_V6_FLOW:
case ESP_V6_FLOW:
memcpy(&rule->key.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&rule->key.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,
sizeof(struct in6_addr));
rule->key.spi = fsp->h_u.ah_ip6_spec.spi;
memcpy(&rule->mask.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&rule->mask.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
sizeof(struct in6_addr));
rule->key.spi = fsp->h_u.ah_ip6_spec.spi;
break;
default:
/* not doing un-parsed flow types */
return -EINVAL;
}
return 0;
}
int gve_get_flow_rule_entry(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
{
struct gve_adminq_queried_flow_rule *rules_cache = priv->flow_rules_cache.rules_cache;
struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
u32 *cache_num = &priv->flow_rules_cache.rules_cache_num;
struct gve_adminq_queried_flow_rule *rule = NULL;
int err = 0;
u32 i;
if (!priv->max_flow_rules)
return -EOPNOTSUPP;
if (!priv->flow_rules_cache.rules_cache_synced ||
fsp->location < be32_to_cpu(rules_cache[0].location) ||
fsp->location > be32_to_cpu(rules_cache[*cache_num - 1].location)) {
err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_RULES, fsp->location);
if (err)
return err;
priv->flow_rules_cache.rules_cache_synced = true;
}
for (i = 0; i < *cache_num; i++) {
if (fsp->location == be32_to_cpu(rules_cache[i].location)) {
rule = &rules_cache[i];
break;
}
}
if (!rule)
return -EINVAL;
err = gve_fill_ethtool_flow_spec(fsp, rule);
return err;
}
int gve_get_flow_rule_ids(struct gve_priv *priv, struct ethtool_rxnfc *cmd, u32 *rule_locs)
{
__be32 *rule_ids_cache = priv->flow_rules_cache.rule_ids_cache;
u32 *cache_num = &priv->flow_rules_cache.rule_ids_cache_num;
u32 starting_rule_id = 0;
u32 i = 0, j = 0;
int err = 0;
if (!priv->max_flow_rules)
return -EOPNOTSUPP;
do {
err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_IDS,
starting_rule_id);
if (err)
return err;
for (i = 0; i < *cache_num; i++) {
if (j >= cmd->rule_cnt)
return -EMSGSIZE;
rule_locs[j++] = be32_to_cpu(rule_ids_cache[i]);
starting_rule_id = be32_to_cpu(rule_ids_cache[i]) + 1;
}
} while (*cache_num != 0);
cmd->data = priv->max_flow_rules;
return err;
}
int gve_add_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
{
struct ethtool_rx_flow_spec *fsp = &cmd->fs;
struct gve_adminq_flow_rule *rule = NULL;
int err;
if (!priv->max_flow_rules)
return -EOPNOTSUPP;
rule = kvzalloc_obj(*rule);
if (!rule)
return -ENOMEM;
err = gve_generate_flow_rule(priv, fsp, rule);
if (err)
goto out;
err = gve_adminq_add_flow_rule(priv, rule, fsp->location);
out:
kvfree(rule);
if (err)
dev_err(&priv->pdev->dev, "Failed to add the flow rule: %u", fsp->location);
return err;
}
int gve_del_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
{
struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
if (!priv->max_flow_rules)
return -EOPNOTSUPP;
return gve_adminq_del_flow_rule(priv, fsp->location);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,164 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2025 Google LLC
*/
#include "gve.h"
#include "gve_adminq.h"
/* Interval to schedule a nic timestamp calibration, 250ms. */
#define GVE_NIC_TS_SYNC_INTERVAL_MS 250
/* Read the nic timestamp from hardware via the admin queue. */
int gve_clock_nic_ts_read(struct gve_priv *priv)
{
u64 nic_raw;
int err;
err = gve_adminq_report_nic_ts(priv, priv->nic_ts_report_bus);
if (err)
return err;
nic_raw = be64_to_cpu(priv->nic_ts_report->nic_timestamp);
WRITE_ONCE(priv->last_sync_nic_counter, nic_raw);
return 0;
}
static int gve_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
return -EOPNOTSUPP;
}
static int gve_ptp_gettimex64(struct ptp_clock_info *info,
struct timespec64 *ts,
struct ptp_system_timestamp *sts)
{
return -EOPNOTSUPP;
}
static int gve_ptp_settime64(struct ptp_clock_info *info,
const struct timespec64 *ts)
{
return -EOPNOTSUPP;
}
static long gve_ptp_do_aux_work(struct ptp_clock_info *info)
{
const struct gve_ptp *ptp = container_of(info, struct gve_ptp, info);
struct gve_priv *priv = ptp->priv;
int err;
if (gve_get_reset_in_progress(priv) || !gve_get_admin_queue_ok(priv))
goto out;
err = gve_clock_nic_ts_read(priv);
if (err && net_ratelimit())
dev_err(&priv->pdev->dev,
"%s read err %d\n", __func__, err);
out:
return msecs_to_jiffies(GVE_NIC_TS_SYNC_INTERVAL_MS);
}
static const struct ptp_clock_info gve_ptp_caps = {
.owner = THIS_MODULE,
.name = "gve clock",
.adjfine = gve_ptp_adjfine,
.gettimex64 = gve_ptp_gettimex64,
.settime64 = gve_ptp_settime64,
.do_aux_work = gve_ptp_do_aux_work,
};
static int gve_ptp_init(struct gve_priv *priv)
{
struct gve_ptp *ptp;
int err;
priv->ptp = kzalloc_obj(*priv->ptp);
if (!priv->ptp)
return -ENOMEM;
ptp = priv->ptp;
ptp->info = gve_ptp_caps;
ptp->clock = ptp_clock_register(&ptp->info, &priv->pdev->dev);
if (IS_ERR(ptp->clock)) {
dev_err(&priv->pdev->dev, "PTP clock registration failed\n");
err = PTR_ERR(ptp->clock);
goto free_ptp;
}
ptp->priv = priv;
return 0;
free_ptp:
kfree(ptp);
priv->ptp = NULL;
return err;
}
static void gve_ptp_release(struct gve_priv *priv)
{
struct gve_ptp *ptp = priv->ptp;
if (!ptp)
return;
if (ptp->clock)
ptp_clock_unregister(ptp->clock);
kfree(ptp);
priv->ptp = NULL;
}
int gve_init_clock(struct gve_priv *priv)
{
int err;
err = gve_ptp_init(priv);
if (err)
return err;
priv->nic_ts_report =
dma_alloc_coherent(&priv->pdev->dev,
sizeof(struct gve_nic_ts_report),
&priv->nic_ts_report_bus,
GFP_KERNEL);
if (!priv->nic_ts_report) {
dev_err(&priv->pdev->dev, "%s dma alloc error\n", __func__);
err = -ENOMEM;
goto release_ptp;
}
err = gve_clock_nic_ts_read(priv);
if (err) {
dev_err(&priv->pdev->dev, "failed to read NIC clock %d\n", err);
goto release_nic_ts_report;
}
ptp_schedule_worker(priv->ptp->clock,
msecs_to_jiffies(GVE_NIC_TS_SYNC_INTERVAL_MS));
return 0;
release_nic_ts_report:
dma_free_coherent(&priv->pdev->dev,
sizeof(struct gve_nic_ts_report),
priv->nic_ts_report, priv->nic_ts_report_bus);
priv->nic_ts_report = NULL;
release_ptp:
gve_ptp_release(priv);
return err;
}
void gve_teardown_clock(struct gve_priv *priv)
{
gve_ptp_release(priv);
if (priv->nic_ts_report) {
dma_free_coherent(&priv->pdev->dev,
sizeof(struct gve_nic_ts_report),
priv->nic_ts_report, priv->nic_ts_report_bus);
priv->nic_ts_report = NULL;
}
}
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2019 Google, Inc.
*/
#ifndef _GVE_REGISTER_H_
#define _GVE_REGISTER_H_
/* Fixed Configuration Registers */
struct gve_registers {
__be32 device_status;
__be32 driver_status;
__be32 max_tx_queues;
__be32 max_rx_queues;
__be32 adminq_pfn;
__be32 adminq_doorbell;
__be32 adminq_event_counter;
u8 reserved[3];
u8 driver_version;
__be32 adminq_base_address_hi;
__be32 adminq_base_address_lo;
__be16 adminq_length;
};
enum gve_device_status_flags {
GVE_DEVICE_STATUS_RESET_MASK = BIT(1),
GVE_DEVICE_STATUS_LINK_STATUS_MASK = BIT(2),
GVE_DEVICE_STATUS_REPORT_STATS_MASK = BIT(3),
GVE_DEVICE_STATUS_DEVICE_IS_RESET = BIT(4),
};
enum gve_driver_status_flags {
GVE_DRIVER_STATUS_RUN_MASK = BIT(0),
GVE_DRIVER_STATUS_RESET_MASK = BIT(1),
};
#endif /* _GVE_REGISTER_H_ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
#include "gve.h"
#include "gve_adminq.h"
#include "gve_utils.h"
bool gve_tx_was_added_to_block(struct gve_priv *priv, int queue_idx)
{
struct gve_notify_block *block =
&priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)];
return block->tx != NULL;
}
void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx)
{
struct gve_notify_block *block =
&priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)];
block->tx = NULL;
}
void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx)
{
unsigned int active_cpus = min_t(int, priv->num_ntfy_blks / 2,
num_online_cpus());
int ntfy_idx = gve_tx_idx_to_ntfy(priv, queue_idx);
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
struct gve_tx_ring *tx = &priv->tx[queue_idx];
block->tx = tx;
tx->ntfy_id = ntfy_idx;
netif_set_xps_queue(priv->dev, get_cpu_mask(ntfy_idx % active_cpus),
queue_idx);
}
bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx)
{
struct gve_notify_block *block =
&priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
return block->rx != NULL;
}
void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx)
{
struct gve_notify_block *block =
&priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
block->rx = NULL;
}
void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx)
{
u32 ntfy_idx = gve_rx_idx_to_ntfy(priv, queue_idx);
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
struct gve_rx_ring *rx = &priv->rx[queue_idx];
block->rx = rx;
rx->ntfy_id = ntfy_idx;
}
struct sk_buff *gve_rx_copy_data(struct net_device *dev, struct napi_struct *napi,
u8 *data, u16 len)
{
struct sk_buff *skb;
skb = napi_alloc_skb(napi, len);
if (unlikely(!skb))
return NULL;
__skb_put(skb, len);
skb_copy_to_linear_data_offset(skb, 0, data, len);
skb->protocol = eth_type_trans(skb, dev);
return skb;
}
struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
struct gve_rx_slot_page_info *page_info, u16 len)
{
void *va = page_info->page_address + page_info->page_offset +
page_info->pad;
return gve_rx_copy_data(dev, napi, va, len);
}
void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info)
{
page_info->pagecnt_bias--;
if (page_info->pagecnt_bias == 0) {
int pagecount = page_count(page_info->page);
/* If we have run out of bias - set it back up to INT_MAX
* minus the existing refs.
*/
page_info->pagecnt_bias = INT_MAX - pagecount;
/* Set pagecount back up to max. */
page_ref_add(page_info->page, INT_MAX - pagecount);
}
}
void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
int (*gve_poll)(struct napi_struct *, int))
{
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
netif_napi_add_locked(priv->dev, &block->napi, gve_poll);
netif_napi_set_irq_locked(&block->napi, block->irq);
enable_irq(block->irq);
}
void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
{
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
disable_irq(block->irq);
netif_napi_del_locked(&block->napi);
}
@@ -0,0 +1,35 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
#ifndef _GVE_UTILS_H
#define _GVE_UTILS_H
#include <linux/etherdevice.h>
#include "gve.h"
bool gve_tx_was_added_to_block(struct gve_priv *priv, int queue_idx);
void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx);
void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx);
bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx);
void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx);
void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx);
struct sk_buff *gve_rx_copy_data(struct net_device *dev, struct napi_struct *napi,
u8 *data, u16 len);
struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
struct gve_rx_slot_page_info *page_info, u16 len);
/* Decrement pagecnt_bias. Set it back to INT_MAX if it reached zero. */
void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info);
void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
int (*gve_poll)(struct napi_struct *, int));
void gve_remove_napi(struct gve_priv *priv, int ntfy_idx);
#endif /* _GVE_UTILS_H */