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