Revert "Merge branch 'gve-add-support-for-ptp-gettimex64'"

This reverts commit 9587ed8137,
reversing changes made to bcdfd9fb10.

Per tglx's objections: https://lore.kernel.org/87mrxtwzz9.ffs@tglx

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-05-20 15:11:51 -07:00
parent bf53bf3320
commit 0ae361f7e4
5 changed files with 98 additions and 346 deletions

View File

@ -792,9 +792,6 @@ struct gve_ptp {
struct ptp_clock_info info;
struct ptp_clock *clock;
struct gve_priv *priv;
struct mutex nic_ts_read_lock; /* Protects nic_ts_report */
struct gve_nic_ts_report *nic_ts_report;
dma_addr_t nic_ts_report_bus;
};
struct gve_priv {
@ -880,14 +877,6 @@ struct gve_priv {
u32 stats_report_trigger_cnt; /* count of device-requested stats-reports since last reset */
u32 suspend_cnt; /* count of times suspended */
u32 resume_cnt; /* count of times resumed */
/* count of cross-timestamps attempted using system timestamps
* from the AQ command
*/
u32 ptp_precise_xtstamps;
/* count of cross-timestamps attempted using system timestamps sampled
* by the driver
*/
u32 ptp_fallback_xtstamps;
struct workqueue_struct *gve_wq;
struct work_struct service_task;
struct work_struct stats_report_task;
@ -934,6 +923,8 @@ struct gve_priv {
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 */
};
@ -1210,7 +1201,7 @@ static inline bool gve_supports_xdp_xmit(struct gve_priv *priv)
static inline bool gve_is_clock_enabled(struct gve_priv *priv)
{
return priv->ptp;
return priv->nic_ts_report;
}
/* gqi napi handler defined in gve_main.c */
@ -1330,9 +1321,14 @@ int gve_flow_rules_reset(struct gve_priv *priv);
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)
{

View File

@ -416,10 +416,16 @@ static bool gve_adminq_wait_for_cmd(struct gve_priv *priv, u32 prod_cnt)
static int gve_adminq_parse_err(struct gve_priv *priv, u32 status)
{
if (status != GVE_ADMINQ_COMMAND_PASSED &&
status != GVE_ADMINQ_COMMAND_UNSET) {
dev_err(&priv->pdev->dev, "AQ command failed with status %d\n", status);
priv->adminq_cmd_fail++;
}
switch (status) {
case GVE_ADMINQ_COMMAND_PASSED:
return 0;
case GVE_ADMINQ_COMMAND_UNSET:
dev_err(&priv->pdev->dev, "parse_aq_err: err and status both unset, this should not be possible.\n");
return -EINVAL;
case GVE_ADMINQ_COMMAND_ERROR_ABORTED:
case GVE_ADMINQ_COMMAND_ERROR_CANCELLED:
@ -449,27 +455,6 @@ static int gve_adminq_parse_err(struct gve_priv *priv, u32 status)
}
}
static bool gve_adminq_is_retryable(enum gve_adminq_opcodes opcode)
{
switch (opcode) {
case GVE_ADMINQ_REPORT_NIC_TIMESTAMP:
return true;
default:
return false;
}
}
static enum gve_adminq_opcodes gve_extract_opcode(union gve_adminq_command *cmd)
{
u32 opcode;
opcode = be32_to_cpu(READ_ONCE(cmd->opcode));
if (opcode == GVE_ADMINQ_EXTENDED_COMMAND)
opcode = be32_to_cpu(cmd->extended_command.inner_opcode);
return opcode;
}
/* Flushes all AQ commands currently queued and waits for them to complete.
* If there are failures, it will return the first error.
*/
@ -492,24 +477,14 @@ static int gve_adminq_kick_and_wait(struct gve_priv *priv)
for (i = tail; i < head; i++) {
union gve_adminq_command *cmd;
u32 status;
int err;
u32 status, err;
cmd = &priv->adminq[i & priv->adminq_mask];
status = be32_to_cpu(READ_ONCE(cmd->status));
err = gve_adminq_parse_err(priv, status);
if (err) {
enum gve_adminq_opcodes opcode = gve_extract_opcode(cmd);
priv->adminq_cmd_fail++;
if (!gve_adminq_is_retryable(opcode) || err != -EAGAIN)
dev_err_ratelimited(&priv->pdev->dev,
"AQ command %d failed with status %d\n",
opcode, status);
if (err)
// Return the first error if we failed.
return err;
}
}
return 0;

View File

@ -411,8 +411,8 @@ static_assert(sizeof(struct gve_adminq_report_nic_ts) == 16);
struct gve_nic_ts_report {
__be64 nic_timestamp; /* NIC clock in nanoseconds */
__be64 pre_cycles; /* System cycle counter before NIC clock read */
__be64 post_cycles; /* System cycle counter after NIC clock read */
__be64 reserved1;
__be64 reserved2;
__be64 reserved3;
__be64 reserved4;
};

View File

@ -46,7 +46,6 @@ static const char gve_gstrings_main_stats[][ETH_GSTRING_LEN] = {
"rx_hsplit_unsplit_pkt",
"interface_up_cnt", "interface_down_cnt", "reset_cnt",
"page_alloc_fail", "dma_mapping_error", "stats_report_trigger_cnt",
"ptp_precise_xtstamps", "ptp_fallback_xtstamps",
};
static const char gve_gstrings_rx_stats[][ETH_GSTRING_LEN] = {
@ -270,8 +269,6 @@ gve_get_ethtool_stats(struct net_device *netdev,
data[i++] = priv->page_alloc_fail;
data[i++] = priv->dma_mapping_error;
data[i++] = priv->stats_report_trigger_cnt;
data[i++] = priv->ptp_precise_xtstamps;
data[i++] = priv->ptp_fallback_xtstamps;
i = GVE_MAIN_STATS_LEN;
rx_base_stats_idx = 0;
@ -975,7 +972,8 @@ static int gve_get_ts_info(struct net_device *netdev,
info->rx_filters |= BIT(HWTSTAMP_FILTER_NONE) |
BIT(HWTSTAMP_FILTER_ALL);
info->phc_index = ptp_clock_index(priv->ptp->clock);
if (priv->ptp)
info->phc_index = ptp_clock_index(priv->ptp->clock);
}
return 0;

View File

@ -10,261 +10,27 @@
/* Interval to schedule a nic timestamp calibration, 250ms. */
#define GVE_NIC_TS_SYNC_INTERVAL_MS 250
/*
* Stores cycle counter samples in get_cycles() units from a
* sandwiched NIC clock read
*/
struct gve_sysclock_sample {
/* Cycle counter from NIC before clock read */
u64 nic_pre_cycles;
/* Cycle counter from NIC after clock read */
u64 nic_post_cycles;
/* Cycle counter from host before issuing AQ command */
cycles_t host_pre_cycles;
/* Cycle counter from host after AQ command returns */
cycles_t host_post_cycles;
};
/*
* Read NIC clock by issuing the AQ command. The command is subject to
* rate limiting and may need to be retried. Requires nic_ts_read_lock
* to be held.
*/
static int gve_ptp_read_timestamp(struct gve_ptp *ptp, cycles_t *pre_cycles,
cycles_t *post_cycles)
{
unsigned long deadline = jiffies + msecs_to_jiffies(100);
unsigned long delay_us = 1000;
int err;
lockdep_assert_held(&ptp->nic_ts_read_lock);
do {
*pre_cycles = get_cycles();
err = gve_adminq_report_nic_ts(ptp->priv,
ptp->nic_ts_report_bus);
/* Prevent get_cycles() from being speculatively executed
* before the AdminQ command
*/
rmb();
*post_cycles = get_cycles();
if (likely(err != -EAGAIN))
return err;
fsleep(delay_us);
/* Exponential backoff */
delay_us *= 2;
} while (time_before(jiffies, deadline));
return -ETIMEDOUT;
}
/* Read the nic timestamp from hardware via the admin queue. */
static int gve_clock_nic_ts_read(struct gve_ptp *ptp, u64 *nic_raw,
struct gve_sysclock_sample *sysclock)
int gve_clock_nic_ts_read(struct gve_priv *priv)
{
cycles_t host_pre_cycles, host_post_cycles;
struct gve_nic_ts_report *ts_report;
u64 nic_raw;
int err;
mutex_lock(&ptp->nic_ts_read_lock);
err = gve_ptp_read_timestamp(ptp, &host_pre_cycles, &host_post_cycles);
if (err) {
dev_err_ratelimited(&ptp->priv->pdev->dev,
"AdminQ timestamp read failed: %d\n", err);
goto out;
}
ts_report = ptp->nic_ts_report;
*nic_raw = be64_to_cpu(ts_report->nic_timestamp);
if (sysclock) {
sysclock->nic_pre_cycles = be64_to_cpu(ts_report->pre_cycles);
sysclock->nic_post_cycles = be64_to_cpu(ts_report->post_cycles);
sysclock->host_pre_cycles = host_pre_cycles;
sysclock->host_post_cycles = host_post_cycles;
}
out:
mutex_unlock(&ptp->nic_ts_read_lock);
return err;
}
struct gve_cycles_to_clock_callback_ctx {
u64 cycles;
};
static int gve_cycles_to_clock_fn(ktime_t *device_time,
struct system_counterval_t *system_counterval,
void *ctx)
{
struct gve_cycles_to_clock_callback_ctx *context = ctx;
*device_time = 0;
system_counterval->cycles = context->cycles;
system_counterval->use_nsecs = false;
if (IS_ENABLED(CONFIG_X86))
system_counterval->cs_id = CSID_X86_TSC;
else if (IS_ENABLED(CONFIG_ARM64))
system_counterval->cs_id = CSID_ARM_ARCH_COUNTER;
else
return -EOPNOTSUPP;
return 0;
}
/*
* Convert a raw cycle count (e.g. from get_cycles()) to the system clock
* type specified by clockid. The system_time_snapshot must be taken before
* the cycle counter is sampled.
*/
static int gve_cycles_to_timespec64(struct gve_priv *priv, clockid_t clockid,
struct system_time_snapshot *snap,
u64 cycles, struct timespec64 *ts)
{
struct gve_cycles_to_clock_callback_ctx ctx = {0};
struct system_device_crosststamp xtstamp;
int err;
ctx.cycles = cycles;
err = get_device_system_crosststamp(gve_cycles_to_clock_fn, &ctx, snap,
&xtstamp);
if (err) {
dev_err_ratelimited(&priv->pdev->dev,
"get_device_system_crosststamp() failed to convert %llu cycles to system time: %d\n",
cycles,
err);
err = gve_adminq_report_nic_ts(priv, priv->nic_ts_report_bus);
if (err)
return err;
}
switch (clockid) {
case CLOCK_REALTIME:
*ts = ktime_to_timespec64(xtstamp.sys_realtime);
break;
case CLOCK_MONOTONIC_RAW:
*ts = ktime_to_timespec64(xtstamp.sys_monoraw);
break;
default:
dev_err_ratelimited(&priv->pdev->dev,
"Cycle count conversion to clockid %d not supported\n",
clockid);
return -EOPNOTSUPP;
}
nic_raw = be64_to_cpu(priv->nic_ts_report->nic_timestamp);
WRITE_ONCE(priv->last_sync_nic_counter, nic_raw);
return 0;
}
static bool
gve_can_use_system_ts_from_device(enum clocksource_ids system_clock_source,
clockid_t clockid)
{
if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC_RAW)
return false;
/* If the system clock source matches the system clock
* returned by the AdminQ command, we can use the system
* timestamps returned by the device, otherwise we have to
* fall back to sampling system time from the host which
* is less accurate.
*/
if (IS_ENABLED(CONFIG_X86))
return system_clock_source == CSID_X86_TSC;
else if (IS_ENABLED(CONFIG_ARM64))
return system_clock_source == CSID_ARM_ARCH_COUNTER;
return false;
}
static int gve_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
return -EOPNOTSUPP;
}
static int gve_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
return -EOPNOTSUPP;
}
static int gve_ptp_gettimex64(struct ptp_clock_info *info,
struct timespec64 *ts,
struct ptp_system_timestamp *sts)
{
struct gve_ptp *ptp = container_of(info, struct gve_ptp, info);
struct gve_sysclock_sample sysclock = {0};
bool use_system_ts_from_device = false;
struct gve_priv *priv = ptp->priv;
struct system_time_snapshot snap;
u64 nic_ts;
int err;
if (sts) {
/* This snapshot is used both to query the current system
* clocksource and to convert the cycle counts returned
* by the AdminQ command to ktime. It does not need to be
* taken inside the retry loop because retries and lock
* contention are expected to be extremely rare.
*
* If the system clock source changes between here and
* when get_device_system_crosststamp() is called,
* get_device_system_crosststamp() will fail which will
* cause one failed sample, and the next one will succeed.
*/
ktime_get_snapshot(&snap);
use_system_ts_from_device =
gve_can_use_system_ts_from_device(snap.cs_id,
sts->clockid);
if (use_system_ts_from_device)
priv->ptp_precise_xtstamps++;
else
priv->ptp_fallback_xtstamps++;
}
if (unlikely(!use_system_ts_from_device))
ptp_read_system_prets(sts);
err = gve_clock_nic_ts_read(ptp, &nic_ts, sts ? &sysclock : NULL);
if (err)
return err;
if (unlikely(!use_system_ts_from_device))
ptp_read_system_postts(sts);
if (sts && likely(use_system_ts_from_device)) {
/* Reject samples with out of order system clock values.
* Firmware must return valid non-zero cycle counts.
*/
if (!(sysclock.host_pre_cycles <= sysclock.nic_pre_cycles &&
sysclock.nic_pre_cycles <= sysclock.nic_post_cycles &&
sysclock.nic_post_cycles <= sysclock.host_post_cycles)) {
dev_err_ratelimited(&priv->pdev->dev,
"AdminQ system clock cycle counts out of order. Expecting %llu <= %llu <= %llu <= %llu\n",
(u64)sysclock.host_pre_cycles,
sysclock.nic_pre_cycles,
sysclock.nic_post_cycles,
(u64)sysclock.host_post_cycles);
return -EBADMSG;
}
err = gve_cycles_to_timespec64(priv, sts->clockid, &snap,
sysclock.nic_pre_cycles,
&sts->pre_ts);
if (err)
return err;
err = gve_cycles_to_timespec64(priv, sts->clockid, &snap,
sysclock.nic_post_cycles,
&sts->post_ts);
if (err)
return err;
}
*ts = ns_to_timespec64(nic_ts);
return 0;
return -EOPNOTSUPP;
}
static int gve_ptp_settime64(struct ptp_clock_info *info,
@ -275,21 +41,17 @@ static int gve_ptp_settime64(struct ptp_clock_info *info,
static long gve_ptp_do_aux_work(struct ptp_clock_info *info)
{
struct gve_ptp *ptp = container_of(info, struct gve_ptp, info);
const struct gve_ptp *ptp = container_of(info, struct gve_ptp, info);
struct gve_priv *priv = ptp->priv;
u64 nic_raw;
int err;
if (gve_get_reset_in_progress(priv) || !gve_get_admin_queue_ok(priv))
goto out;
err = gve_clock_nic_ts_read(ptp, &nic_raw, NULL);
if (err) {
dev_err_ratelimited(&priv->pdev->dev, "%s read err %d\n",
__func__, err);
goto out;
}
WRITE_ONCE(priv->last_sync_nic_counter, nic_raw);
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);
@ -298,78 +60,99 @@ static long gve_ptp_do_aux_work(struct ptp_clock_info *info)
static const struct ptp_clock_info gve_ptp_caps = {
.owner = THIS_MODULE,
.name = "gve clock",
.adjfine = gve_ptp_adjfine,
.adjtime = gve_ptp_adjtime,
.gettimex64 = gve_ptp_gettimex64,
.settime64 = gve_ptp_settime64,
.do_aux_work = gve_ptp_do_aux_work,
};
int gve_init_clock(struct gve_priv *priv)
static int gve_ptp_init(struct gve_priv *priv)
{
struct gve_ptp *ptp;
u64 nic_raw;
int err;
ptp = kzalloc_obj(*priv->ptp);
if (!ptp)
priv->ptp = kzalloc_obj(*priv->ptp);
if (!priv->ptp)
return -ENOMEM;
ptp = priv->ptp;
ptp->info = gve_ptp_caps;
ptp->priv = priv;
mutex_init(&ptp->nic_ts_read_lock);
ptp->nic_ts_report =
dma_alloc_coherent(&priv->pdev->dev,
sizeof(struct gve_nic_ts_report),
&ptp->nic_ts_report_bus, GFP_KERNEL);
if (!ptp->nic_ts_report) {
dev_err(&priv->pdev->dev, "%s dma alloc error\n", __func__);
err = -ENOMEM;
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;
}
err = gve_clock_nic_ts_read(ptp, &nic_raw, NULL);
if (err) {
dev_err(&priv->pdev->dev, "failed to read NIC clock %d\n", err);
goto free_dma_mem;
}
WRITE_ONCE(priv->last_sync_nic_counter, nic_raw);
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_dma_mem;
}
priv->ptp = ptp;
ptp_schedule_worker(ptp->clock,
msecs_to_jiffies(GVE_NIC_TS_SYNC_INTERVAL_MS));
ptp->priv = priv;
return 0;
free_dma_mem:
dma_free_coherent(&priv->pdev->dev, sizeof(struct gve_nic_ts_report),
ptp->nic_ts_report, ptp->nic_ts_report_bus);
ptp->nic_ts_report = NULL;
free_ptp:
mutex_destroy(&ptp->nic_ts_read_lock);
kfree(ptp);
priv->ptp = NULL;
return err;
}
void gve_teardown_clock(struct gve_priv *priv)
static void gve_ptp_release(struct gve_priv *priv)
{
struct gve_ptp *ptp = priv->ptp;
if (!ptp)
return;
priv->ptp = NULL;
ptp_clock_unregister(ptp->clock);
dma_free_coherent(&priv->pdev->dev, sizeof(struct gve_nic_ts_report),
ptp->nic_ts_report, ptp->nic_ts_report_bus);
ptp->nic_ts_report = NULL;
mutex_destroy(&ptp->nic_ts_read_lock);
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;
}
}