]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
gve: Implement ndo_hwtstamp_get/set for RX timestamping
authorJohn Fraker <jfraker@google.com>
Sat, 14 Jun 2025 00:07:53 +0000 (00:07 +0000)
committerJakub Kicinski <kuba@kernel.org>
Mon, 16 Jun 2025 22:27:24 +0000 (15:27 -0700)
Implement ndo_hwtstamp_get/set to enable hardware RX timestamping,
providing support for SIOC[SG]HWTSTAMP IOCTLs. Included with this support
is the small change necessary to read the rx timestamp out of the rx
descriptor, now that timestamps start being enabled. The gve clock is
only used for hardware timestamps, so started when timestamps are
requested and stopped when not needed.

This version only supports RX hardware timestamping with the rx filter
HWTSTAMP_FILTER_ALL. If the user attempts to configure a more
restrictive filter, the filter will be set to HWTSTAMP_FILTER_ALL in the
returned structure.

Signed-off-by: John Fraker <jfraker@google.com>
Signed-off-by: Ziwei Xiao <ziweixiao@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
Link: https://patch.msgid.link/20250614000754.164827-8-hramamurthy@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/google/gve/gve.h
drivers/net/ethernet/google/gve/gve_desc_dqo.h
drivers/net/ethernet/google/gve/gve_main.c
drivers/net/ethernet/google/gve/gve_rx_dqo.c

index 527e17da60bcf6c47fac5ba37fcd7ad97d4c04d3..be4b5791c245c606ebbb4a46dd92eb8f6943b293 100644 (file)
@@ -11,6 +11,7 @@
 #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>
@@ -882,6 +883,7 @@ struct gve_priv {
        /* 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 */
index f79cd059111038929ebc5764e1f1de26e634aec8..d17da841b5a03182732e9e64c74a4e8b9b1984bf 100644 (file)
@@ -247,7 +247,8 @@ struct gve_rx_compl_desc_dqo {
        };
        __le32 hash;
        __le32 reserved6;
-       __le64 reserved7;
+       __le32 reserved7;
+       __le32 ts; /* timestamp in nanosecs */
 } __packed;
 
 static_assert(sizeof(struct gve_rx_compl_desc_dqo) == 32);
index bc2f36962ee8d6a9dd9254523583b395a437f2a9..7fff1409b1211ec5e4e7c094e1b0fa7923338b05 100644 (file)
@@ -727,6 +727,7 @@ static void gve_teardown_device_resources(struct gve_priv *priv)
        gve_free_counter_array(priv);
        gve_free_notify_blocks(priv);
        gve_free_stats_report(priv);
+       gve_teardown_clock(priv);
        gve_clear_device_resources_ok(priv);
 }
 
@@ -2047,6 +2048,46 @@ revert_features:
        return err;
 }
 
+static int gve_get_ts_config(struct net_device *dev,
+                            struct kernel_hwtstamp_config *kernel_config)
+{
+       struct gve_priv *priv = netdev_priv(dev);
+
+       *kernel_config = priv->ts_config;
+       return 0;
+}
+
+static int gve_set_ts_config(struct net_device *dev,
+                            struct kernel_hwtstamp_config *kernel_config,
+                            struct netlink_ext_ack *extack)
+{
+       struct gve_priv *priv = netdev_priv(dev);
+
+       if (kernel_config->tx_type != HWTSTAMP_TX_OFF) {
+               NL_SET_ERR_MSG_MOD(extack, "TX timestamping is not supported");
+               return -ERANGE;
+       }
+
+       if (kernel_config->rx_filter != HWTSTAMP_FILTER_NONE) {
+               if (!priv->nic_ts_report) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "RX timestamping is not supported");
+                       kernel_config->rx_filter = HWTSTAMP_FILTER_NONE;
+                       return -EOPNOTSUPP;
+               }
+
+               kernel_config->rx_filter = HWTSTAMP_FILTER_ALL;
+               gve_clock_nic_ts_read(priv);
+               ptp_schedule_worker(priv->ptp->clock, 0);
+       } else {
+               ptp_cancel_worker_sync(priv->ptp->clock);
+       }
+
+       priv->ts_config.rx_filter = kernel_config->rx_filter;
+
+       return 0;
+}
+
 static const struct net_device_ops gve_netdev_ops = {
        .ndo_start_xmit         =       gve_start_xmit,
        .ndo_features_check     =       gve_features_check,
@@ -2058,6 +2099,8 @@ static const struct net_device_ops gve_netdev_ops = {
        .ndo_bpf                =       gve_xdp,
        .ndo_xdp_xmit           =       gve_xdp_xmit,
        .ndo_xsk_wakeup         =       gve_xsk_wakeup,
+       .ndo_hwtstamp_get       =       gve_get_ts_config,
+       .ndo_hwtstamp_set       =       gve_set_ts_config,
 };
 
 static void gve_handle_status(struct gve_priv *priv, u32 status)
@@ -2277,6 +2320,9 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
                priv->rx_coalesce_usecs = GVE_RX_IRQ_RATELIMIT_US_DQO;
        }
 
+       priv->ts_config.tx_type = HWTSTAMP_TX_OFF;
+       priv->ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
+
 setup_device:
        gve_set_netdev_xdp_features(priv);
        err = gve_setup_device_resources(priv);
index 9aadf8435f8b4ac6858804cd7223a370f654b115..0be41a0cdd15a40779f2ec79efd3c88d49bacbfb 100644 (file)
@@ -450,7 +450,7 @@ static void gve_rx_skb_hash(struct sk_buff *skb,
  * Note that this means if the time delta between packet reception and the last
  * clock read is greater than ~2 seconds, this will provide invalid results.
  */
-static void __maybe_unused gve_rx_skb_hwtstamp(struct gve_rx_ring *rx, u32 hwts)
+static void gve_rx_skb_hwtstamp(struct gve_rx_ring *rx, u32 hwts)
 {
        u64 last_read = READ_ONCE(rx->gve->last_sync_nic_counter);
        struct sk_buff *skb = rx->ctx.skb_head;
@@ -790,6 +790,9 @@ static int gve_rx_complete_skb(struct gve_rx_ring *rx, struct napi_struct *napi,
        if (feat & NETIF_F_RXCSUM)
                gve_rx_skb_csum(rx->ctx.skb_head, desc, ptype);
 
+       if (rx->gve->ts_config.rx_filter == HWTSTAMP_FILTER_ALL)
+               gve_rx_skb_hwtstamp(rx, le32_to_cpu(desc->ts));
+
        /* RSC packets must set gso_size otherwise the TCP stack will complain
         * that packets are larger than MTU.
         */