Commit 0550890b authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'gve-add-rx-hw-timestamping-support'

Ziwei Xiao says:

====================
gve: Add Rx HW timestamping support

This patch series add the support of Rx HW timestamping, which sends
adminq commands periodically to the device for clock synchronization with
the NIC.

The ability to read the PHC from user space will be added in the
future patch series when adding the actual PTP support. For this patch
series, it's adding the initial ptp to utilize the ptp_schedule_worker
to schedule the work of syncing the NIC clock.
====================

Link: https://patch.msgid.link/20250614000754.164827-1-hramamurthy@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 7768c5f4 a471e7f8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ 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)"
+3 −1
Original line number Diff line number Diff line
# Makefile for the Google virtual Ethernet (gve) driver

obj-$(CONFIG_GVE) += gve.o
gve-objs := 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-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
+35 −0
Original line number Diff line number Diff line
@@ -11,7 +11,9 @@
#include <linux/dmapool.h>
#include <linux/ethtool_netlink.h>
#include <linux/netdevice.h>
#include <linux/net_tstamp.h>
#include <linux/pci.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/u64_stats_sync.h>
#include <net/page_pool/helpers.h>
#include <net/xdp.h>
@@ -750,6 +752,12 @@ struct gve_rss_config {
	u32 *hash_lut;
};

struct gve_ptp {
	struct ptp_clock_info info;
	struct ptp_clock *clock;
	struct gve_priv *priv;
};

struct gve_priv {
	struct net_device *dev;
	struct gve_tx_ring *tx; /* array of tx_cfg.num_queues */
@@ -813,6 +821,7 @@ struct gve_priv {
	u32 adminq_set_driver_parameter_cnt;
	u32 adminq_report_stats_cnt;
	u32 adminq_report_link_speed_cnt;
	u32 adminq_report_nic_timestamp_cnt;
	u32 adminq_get_ptype_map_cnt;
	u32 adminq_verify_driver_compatibility_cnt;
	u32 adminq_query_flow_rules_cnt;
@@ -870,6 +879,14 @@ struct gve_priv {
	u16 rss_lut_size;
	bool cache_rss_config;
	struct gve_rss_config rss_config;

	/* True if the device supports reading the nic clock */
	bool nic_timestamp_supported;
	struct gve_ptp *ptp;
	struct kernel_hwtstamp_config ts_config;
	struct gve_nic_ts_report *nic_ts_report;
	dma_addr_t nic_ts_report_bus;
	u64 last_sync_nic_counter; /* Clock counter from last NIC TS report */
};

enum gve_service_task_flags_bit {
@@ -1249,6 +1266,24 @@ int gve_del_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd);
int gve_flow_rules_reset(struct gve_priv *priv);
/* RSS config */
int gve_init_rss_config(struct gve_priv *priv, u16 num_queues);
/* PTP and timestamping */
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
int gve_clock_nic_ts_read(struct gve_priv *priv);
int gve_init_clock(struct gve_priv *priv);
void gve_teardown_clock(struct gve_priv *priv);
#else /* CONFIG_PTP_1588_CLOCK */
static inline int gve_clock_nic_ts_read(struct gve_priv *priv)
{
	return -EOPNOTSUPP;
}

static inline int gve_init_clock(struct gve_priv *priv)
{
	return 0;
}

static inline void gve_teardown_clock(struct gve_priv *priv) { }
#endif /* CONFIG_PTP_1588_CLOCK */
/* report stats handling */
void gve_handle_report_stats(struct gve_priv *priv);
/* exported by ethtool.c */
+86 −12
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ void gve_parse_device_option(struct gve_priv *priv,
			     struct gve_device_option_buffer_sizes **dev_op_buffer_sizes,
			     struct gve_device_option_flow_steering **dev_op_flow_steering,
			     struct gve_device_option_rss_config **dev_op_rss_config,
			     struct gve_device_option_nic_timestamp **dev_op_nic_timestamp,
			     struct gve_device_option_modify_ring **dev_op_modify_ring)
{
	u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
@@ -225,6 +226,23 @@ void gve_parse_device_option(struct gve_priv *priv,
				 "RSS config");
		*dev_op_rss_config = (void *)(option + 1);
		break;
	case GVE_DEV_OPT_ID_NIC_TIMESTAMP:
		if (option_length < sizeof(**dev_op_nic_timestamp) ||
		    req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_NIC_TIMESTAMP) {
			dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT,
				 "Nic Timestamp",
				 (int)sizeof(**dev_op_nic_timestamp),
				 GVE_DEV_OPT_REQ_FEAT_MASK_NIC_TIMESTAMP,
				 option_length, req_feat_mask);
			break;
		}

		if (option_length > sizeof(**dev_op_nic_timestamp))
			dev_warn(&priv->pdev->dev,
				 GVE_DEVICE_OPTION_TOO_BIG_FMT,
				 "Nic Timestamp");
		*dev_op_nic_timestamp = (void *)(option + 1);
		break;
	default:
		/* If we don't recognize the option just continue
		 * without doing anything.
@@ -246,6 +264,7 @@ gve_process_device_options(struct gve_priv *priv,
			   struct gve_device_option_buffer_sizes **dev_op_buffer_sizes,
			   struct gve_device_option_flow_steering **dev_op_flow_steering,
			   struct gve_device_option_rss_config **dev_op_rss_config,
			   struct gve_device_option_nic_timestamp **dev_op_nic_timestamp,
			   struct gve_device_option_modify_ring **dev_op_modify_ring)
{
	const int num_options = be16_to_cpu(descriptor->num_device_options);
@@ -269,6 +288,7 @@ gve_process_device_options(struct gve_priv *priv,
					dev_op_dqo_rda, dev_op_jumbo_frames,
					dev_op_dqo_qpl, dev_op_buffer_sizes,
					dev_op_flow_steering, dev_op_rss_config,
					dev_op_nic_timestamp,
					dev_op_modify_ring);
		dev_opt = next_opt;
	}
@@ -306,6 +326,7 @@ int gve_adminq_alloc(struct device *dev, struct gve_priv *priv)
	priv->adminq_set_driver_parameter_cnt = 0;
	priv->adminq_report_stats_cnt = 0;
	priv->adminq_report_link_speed_cnt = 0;
	priv->adminq_report_nic_timestamp_cnt = 0;
	priv->adminq_get_ptype_map_cnt = 0;
	priv->adminq_query_flow_rules_cnt = 0;
	priv->adminq_cfg_flow_rule_cnt = 0;
@@ -442,6 +463,8 @@ static int gve_adminq_kick_and_wait(struct gve_priv *priv)
	int tail, head;
	int i;

	lockdep_assert_held(&priv->adminq_lock);

	tail = ioread32be(&priv->reg_bar0->adminq_event_counter);
	head = priv->adminq_prod_cnt;

@@ -467,9 +490,6 @@ static int gve_adminq_kick_and_wait(struct gve_priv *priv)
	return 0;
}

/* This function is not threadsafe - the caller is responsible for any
 * necessary locks.
 */
static int gve_adminq_issue_cmd(struct gve_priv *priv,
				union gve_adminq_command *cmd_orig)
{
@@ -477,6 +497,8 @@ static int gve_adminq_issue_cmd(struct gve_priv *priv,
	u32 opcode;
	u32 tail;

	lockdep_assert_held(&priv->adminq_lock);

	tail = ioread32be(&priv->reg_bar0->adminq_event_counter);

	// Check if next command will overflow the buffer.
@@ -544,6 +566,9 @@ static int gve_adminq_issue_cmd(struct gve_priv *priv,
	case GVE_ADMINQ_REPORT_LINK_SPEED:
		priv->adminq_report_link_speed_cnt++;
		break;
	case GVE_ADMINQ_REPORT_NIC_TIMESTAMP:
		priv->adminq_report_nic_timestamp_cnt++;
		break;
	case GVE_ADMINQ_GET_PTYPE_MAP:
		priv->adminq_get_ptype_map_cnt++;
		break;
@@ -709,13 +734,19 @@ int gve_adminq_create_tx_queues(struct gve_priv *priv, u32 start_id, u32 num_que
	int err;
	int i;

	mutex_lock(&priv->adminq_lock);

	for (i = start_id; i < start_id + num_queues; i++) {
		err = gve_adminq_create_tx_queue(priv, i);
		if (err)
			return err;
			goto out;
	}

	return gve_adminq_kick_and_wait(priv);
	err = gve_adminq_kick_and_wait(priv);

out:
	mutex_unlock(&priv->adminq_lock);
	return err;
}

static void gve_adminq_get_create_rx_queue_cmd(struct gve_priv *priv,
@@ -788,13 +819,19 @@ int gve_adminq_create_rx_queues(struct gve_priv *priv, u32 num_queues)
	int err;
	int i;

	mutex_lock(&priv->adminq_lock);

	for (i = 0; i < num_queues; i++) {
		err = gve_adminq_create_rx_queue(priv, i);
		if (err)
			return err;
			goto out;
	}

	return gve_adminq_kick_and_wait(priv);
	err = gve_adminq_kick_and_wait(priv);

out:
	mutex_unlock(&priv->adminq_lock);
	return err;
}

static int gve_adminq_destroy_tx_queue(struct gve_priv *priv, u32 queue_index)
@@ -820,13 +857,19 @@ int gve_adminq_destroy_tx_queues(struct gve_priv *priv, u32 start_id, u32 num_qu
	int err;
	int i;

	mutex_lock(&priv->adminq_lock);

	for (i = start_id; i < start_id + num_queues; i++) {
		err = gve_adminq_destroy_tx_queue(priv, i);
		if (err)
			return err;
			goto out;
	}

	return gve_adminq_kick_and_wait(priv);
	err = gve_adminq_kick_and_wait(priv);

out:
	mutex_unlock(&priv->adminq_lock);
	return err;
}

static void gve_adminq_make_destroy_rx_queue_cmd(union gve_adminq_command *cmd,
@@ -861,13 +904,19 @@ int gve_adminq_destroy_rx_queues(struct gve_priv *priv, u32 num_queues)
	int err;
	int i;

	mutex_lock(&priv->adminq_lock);

	for (i = 0; i < num_queues; i++) {
		err = gve_adminq_destroy_rx_queue(priv, i);
		if (err)
			return err;
			goto out;
	}

	return gve_adminq_kick_and_wait(priv);
	err = gve_adminq_kick_and_wait(priv);

out:
	mutex_unlock(&priv->adminq_lock);
	return err;
}

static void gve_set_default_desc_cnt(struct gve_priv *priv,
@@ -904,6 +953,8 @@ static void gve_enable_supported_features(struct gve_priv *priv,
					  *dev_op_flow_steering,
					  const struct gve_device_option_rss_config
					  *dev_op_rss_config,
					  const struct gve_device_option_nic_timestamp
					  *dev_op_nic_timestamp,
					  const struct gve_device_option_modify_ring
					  *dev_op_modify_ring)
{
@@ -980,10 +1031,15 @@ static void gve_enable_supported_features(struct gve_priv *priv,
			"RSS device option enabled with key size of %u, lut size of %u.\n",
			priv->rss_key_size, priv->rss_lut_size);
	}

	if (dev_op_nic_timestamp &&
	    (supported_features_mask & GVE_SUP_NIC_TIMESTAMP_MASK))
		priv->nic_timestamp_supported = true;
}

int gve_adminq_describe_device(struct gve_priv *priv)
{
	struct gve_device_option_nic_timestamp *dev_op_nic_timestamp = NULL;
	struct gve_device_option_flow_steering *dev_op_flow_steering = NULL;
	struct gve_device_option_buffer_sizes *dev_op_buffer_sizes = NULL;
	struct gve_device_option_jumbo_frames *dev_op_jumbo_frames = NULL;
@@ -1024,6 +1080,7 @@ int gve_adminq_describe_device(struct gve_priv *priv)
					 &dev_op_buffer_sizes,
					 &dev_op_flow_steering,
					 &dev_op_rss_config,
					 &dev_op_nic_timestamp,
					 &dev_op_modify_ring);
	if (err)
		goto free_device_descriptor;
@@ -1088,7 +1145,8 @@ int gve_adminq_describe_device(struct gve_priv *priv)
	gve_enable_supported_features(priv, supported_features_mask,
				      dev_op_jumbo_frames, dev_op_dqo_qpl,
				      dev_op_buffer_sizes, dev_op_flow_steering,
				      dev_op_rss_config, dev_op_modify_ring);
				      dev_op_rss_config, dev_op_nic_timestamp,
				      dev_op_modify_ring);

free_device_descriptor:
	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
@@ -1200,6 +1258,22 @@ int gve_adminq_report_link_speed(struct gve_priv *priv)
	return err;
}

int gve_adminq_report_nic_ts(struct gve_priv *priv,
			     dma_addr_t nic_ts_report_addr)
{
	union gve_adminq_command cmd;

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = cpu_to_be32(GVE_ADMINQ_REPORT_NIC_TIMESTAMP);
	cmd.report_nic_ts = (struct gve_adminq_report_nic_ts) {
		.nic_ts_report_len =
			cpu_to_be64(sizeof(struct gve_nic_ts_report)),
		.nic_ts_report_addr = cpu_to_be64(nic_ts_report_addr),
	};

	return gve_adminq_execute_cmd(priv, &cmd);
}

int gve_adminq_get_ptype_map_dqo(struct gve_priv *priv,
				 struct gve_ptype_lut *ptype_lut)
{
+28 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ enum gve_adminq_opcodes {
	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 */
@@ -174,6 +175,12 @@ struct gve_device_option_rss_config {

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
@@ -192,6 +199,7 @@ enum gve_dev_opt_id {
	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,
};

@@ -206,6 +214,7 @@ enum gve_dev_opt_req_feat_mask {
	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 {
@@ -214,6 +223,7 @@ enum gve_sup_feature_mask {
	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
@@ -392,6 +402,21 @@ struct gve_adminq_report_link_speed {

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;
@@ -585,6 +610,7 @@ union gve_adminq_command {
			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;
		};
	};
@@ -624,6 +650,8 @@ 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,
Loading