1acd16380SHarshitha Ramamurthy // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2acd16380SHarshitha Ramamurthy /* Google virtual Ethernet (gve) driver
3acd16380SHarshitha Ramamurthy *
4acd16380SHarshitha Ramamurthy * Copyright (C) 2025 Google LLC
5acd16380SHarshitha Ramamurthy */
6acd16380SHarshitha Ramamurthy
7acd16380SHarshitha Ramamurthy #include "gve.h"
8*c51b7bf8SKevin Yang #include "gve_adminq.h"
9*c51b7bf8SKevin Yang
10*c51b7bf8SKevin Yang /* Interval to schedule a nic timestamp calibration, 250ms. */
11*c51b7bf8SKevin Yang #define GVE_NIC_TS_SYNC_INTERVAL_MS 250
12*c51b7bf8SKevin Yang
13*c51b7bf8SKevin Yang /* Read the nic timestamp from hardware via the admin queue. */
gve_clock_nic_ts_read(struct gve_priv * priv)14*c51b7bf8SKevin Yang int gve_clock_nic_ts_read(struct gve_priv *priv)
15*c51b7bf8SKevin Yang {
16*c51b7bf8SKevin Yang u64 nic_raw;
17*c51b7bf8SKevin Yang int err;
18*c51b7bf8SKevin Yang
19*c51b7bf8SKevin Yang err = gve_adminq_report_nic_ts(priv, priv->nic_ts_report_bus);
20*c51b7bf8SKevin Yang if (err)
21*c51b7bf8SKevin Yang return err;
22*c51b7bf8SKevin Yang
23*c51b7bf8SKevin Yang nic_raw = be64_to_cpu(priv->nic_ts_report->nic_timestamp);
24*c51b7bf8SKevin Yang WRITE_ONCE(priv->last_sync_nic_counter, nic_raw);
25*c51b7bf8SKevin Yang
26*c51b7bf8SKevin Yang return 0;
27*c51b7bf8SKevin Yang }
28*c51b7bf8SKevin Yang
gve_ptp_do_aux_work(struct ptp_clock_info * info)29*c51b7bf8SKevin Yang static long gve_ptp_do_aux_work(struct ptp_clock_info *info)
30*c51b7bf8SKevin Yang {
31*c51b7bf8SKevin Yang const struct gve_ptp *ptp = container_of(info, struct gve_ptp, info);
32*c51b7bf8SKevin Yang struct gve_priv *priv = ptp->priv;
33*c51b7bf8SKevin Yang int err;
34*c51b7bf8SKevin Yang
35*c51b7bf8SKevin Yang if (gve_get_reset_in_progress(priv) || !gve_get_admin_queue_ok(priv))
36*c51b7bf8SKevin Yang goto out;
37*c51b7bf8SKevin Yang
38*c51b7bf8SKevin Yang err = gve_clock_nic_ts_read(priv);
39*c51b7bf8SKevin Yang if (err && net_ratelimit())
40*c51b7bf8SKevin Yang dev_err(&priv->pdev->dev,
41*c51b7bf8SKevin Yang "%s read err %d\n", __func__, err);
42*c51b7bf8SKevin Yang
43*c51b7bf8SKevin Yang out:
44*c51b7bf8SKevin Yang return msecs_to_jiffies(GVE_NIC_TS_SYNC_INTERVAL_MS);
45*c51b7bf8SKevin Yang }
46acd16380SHarshitha Ramamurthy
47acd16380SHarshitha Ramamurthy static const struct ptp_clock_info gve_ptp_caps = {
48acd16380SHarshitha Ramamurthy .owner = THIS_MODULE,
49acd16380SHarshitha Ramamurthy .name = "gve clock",
50*c51b7bf8SKevin Yang .do_aux_work = gve_ptp_do_aux_work,
51acd16380SHarshitha Ramamurthy };
52acd16380SHarshitha Ramamurthy
gve_ptp_init(struct gve_priv * priv)53*c51b7bf8SKevin Yang static int gve_ptp_init(struct gve_priv *priv)
54acd16380SHarshitha Ramamurthy {
55acd16380SHarshitha Ramamurthy struct gve_ptp *ptp;
56acd16380SHarshitha Ramamurthy int err;
57acd16380SHarshitha Ramamurthy
58acd16380SHarshitha Ramamurthy if (!priv->nic_timestamp_supported) {
59acd16380SHarshitha Ramamurthy dev_dbg(&priv->pdev->dev, "Device does not support PTP\n");
60acd16380SHarshitha Ramamurthy return -EOPNOTSUPP;
61acd16380SHarshitha Ramamurthy }
62acd16380SHarshitha Ramamurthy
63acd16380SHarshitha Ramamurthy priv->ptp = kzalloc(sizeof(*priv->ptp), GFP_KERNEL);
64acd16380SHarshitha Ramamurthy if (!priv->ptp)
65acd16380SHarshitha Ramamurthy return -ENOMEM;
66acd16380SHarshitha Ramamurthy
67acd16380SHarshitha Ramamurthy ptp = priv->ptp;
68acd16380SHarshitha Ramamurthy ptp->info = gve_ptp_caps;
69acd16380SHarshitha Ramamurthy ptp->clock = ptp_clock_register(&ptp->info, &priv->pdev->dev);
70acd16380SHarshitha Ramamurthy
71acd16380SHarshitha Ramamurthy if (IS_ERR(ptp->clock)) {
72acd16380SHarshitha Ramamurthy dev_err(&priv->pdev->dev, "PTP clock registration failed\n");
73acd16380SHarshitha Ramamurthy err = PTR_ERR(ptp->clock);
74acd16380SHarshitha Ramamurthy goto free_ptp;
75acd16380SHarshitha Ramamurthy }
76acd16380SHarshitha Ramamurthy
77acd16380SHarshitha Ramamurthy ptp->priv = priv;
78acd16380SHarshitha Ramamurthy return 0;
79acd16380SHarshitha Ramamurthy
80acd16380SHarshitha Ramamurthy free_ptp:
81acd16380SHarshitha Ramamurthy kfree(ptp);
82acd16380SHarshitha Ramamurthy priv->ptp = NULL;
83acd16380SHarshitha Ramamurthy return err;
84acd16380SHarshitha Ramamurthy }
85acd16380SHarshitha Ramamurthy
gve_ptp_release(struct gve_priv * priv)86*c51b7bf8SKevin Yang static void gve_ptp_release(struct gve_priv *priv)
87acd16380SHarshitha Ramamurthy {
88acd16380SHarshitha Ramamurthy struct gve_ptp *ptp = priv->ptp;
89acd16380SHarshitha Ramamurthy
90acd16380SHarshitha Ramamurthy if (!ptp)
91acd16380SHarshitha Ramamurthy return;
92acd16380SHarshitha Ramamurthy
93acd16380SHarshitha Ramamurthy if (ptp->clock)
94acd16380SHarshitha Ramamurthy ptp_clock_unregister(ptp->clock);
95acd16380SHarshitha Ramamurthy
96acd16380SHarshitha Ramamurthy kfree(ptp);
97acd16380SHarshitha Ramamurthy priv->ptp = NULL;
98acd16380SHarshitha Ramamurthy }
99*c51b7bf8SKevin Yang
gve_init_clock(struct gve_priv * priv)100*c51b7bf8SKevin Yang int gve_init_clock(struct gve_priv *priv)
101*c51b7bf8SKevin Yang {
102*c51b7bf8SKevin Yang int err;
103*c51b7bf8SKevin Yang
104*c51b7bf8SKevin Yang if (!priv->nic_timestamp_supported)
105*c51b7bf8SKevin Yang return 0;
106*c51b7bf8SKevin Yang
107*c51b7bf8SKevin Yang err = gve_ptp_init(priv);
108*c51b7bf8SKevin Yang if (err)
109*c51b7bf8SKevin Yang return err;
110*c51b7bf8SKevin Yang
111*c51b7bf8SKevin Yang priv->nic_ts_report =
112*c51b7bf8SKevin Yang dma_alloc_coherent(&priv->pdev->dev,
113*c51b7bf8SKevin Yang sizeof(struct gve_nic_ts_report),
114*c51b7bf8SKevin Yang &priv->nic_ts_report_bus,
115*c51b7bf8SKevin Yang GFP_KERNEL);
116*c51b7bf8SKevin Yang if (!priv->nic_ts_report) {
117*c51b7bf8SKevin Yang dev_err(&priv->pdev->dev, "%s dma alloc error\n", __func__);
118*c51b7bf8SKevin Yang err = -ENOMEM;
119*c51b7bf8SKevin Yang goto release_ptp;
120*c51b7bf8SKevin Yang }
121*c51b7bf8SKevin Yang
122*c51b7bf8SKevin Yang return 0;
123*c51b7bf8SKevin Yang
124*c51b7bf8SKevin Yang release_ptp:
125*c51b7bf8SKevin Yang gve_ptp_release(priv);
126*c51b7bf8SKevin Yang return err;
127*c51b7bf8SKevin Yang }
128*c51b7bf8SKevin Yang
gve_teardown_clock(struct gve_priv * priv)129*c51b7bf8SKevin Yang void gve_teardown_clock(struct gve_priv *priv)
130*c51b7bf8SKevin Yang {
131*c51b7bf8SKevin Yang gve_ptp_release(priv);
132*c51b7bf8SKevin Yang
133*c51b7bf8SKevin Yang if (priv->nic_ts_report) {
134*c51b7bf8SKevin Yang dma_free_coherent(&priv->pdev->dev,
135*c51b7bf8SKevin Yang sizeof(struct gve_nic_ts_report),
136*c51b7bf8SKevin Yang priv->nic_ts_report, priv->nic_ts_report_bus);
137*c51b7bf8SKevin Yang priv->nic_ts_report = NULL;
138*c51b7bf8SKevin Yang }
139*c51b7bf8SKevin Yang }
140