1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Expose virtio_rtc clocks as PTP clocks.
4 *
5 * Copyright (C) 2022-2023 OpenSynergy GmbH
6 * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
7 *
8 * Derived from ptp_kvm_common.c, virtual PTP 1588 clock for use with KVM
9 * guests.
10 *
11 * Copyright (C) 2017 Red Hat Inc.
12 */
13
14 #include <linux/device.h>
15 #include <linux/err.h>
16 #include <linux/ptp_clock_kernel.h>
17
18 #include <uapi/linux/virtio_rtc.h>
19
20 #include "virtio_rtc_internal.h"
21
22 /**
23 * struct viortc_ptp_clock - PTP clock abstraction
24 * @ptp_clock: PTP clock handle for unregistering
25 * @viortc: virtio_rtc device data
26 * @ptp_info: PTP clock description
27 * @vio_clk_id: virtio_rtc clock id
28 * @have_cross: device supports crosststamp with available HW counter
29 */
30 struct viortc_ptp_clock {
31 struct ptp_clock *ptp_clock;
32 struct viortc_dev *viortc;
33 struct ptp_clock_info ptp_info;
34 u16 vio_clk_id;
35 bool have_cross;
36 };
37
38 /**
39 * struct viortc_ptp_cross_ctx - context for get_device_system_crosststamp()
40 * @device_time: device clock reading
41 * @system_counterval: HW counter value at device_time
42 *
43 * Provides the already obtained crosststamp to get_device_system_crosststamp().
44 */
45 struct viortc_ptp_cross_ctx {
46 ktime_t device_time;
47 struct system_counterval_t system_counterval;
48 };
49
50 /* Weak function in case get_device_system_crosststamp() is not supported */
viortc_hw_xtstamp_params(u8 * hw_counter,enum clocksource_ids * cs_id)51 int __weak viortc_hw_xtstamp_params(u8 *hw_counter, enum clocksource_ids *cs_id)
52 {
53 return -EOPNOTSUPP;
54 }
55
56 /**
57 * viortc_ptp_get_time_fn() - callback for get_device_system_crosststamp()
58 * @device_time: device clock reading
59 * @system_counterval: HW counter value at device_time
60 * @ctx: context with already obtained crosststamp
61 *
62 * Return: zero (success).
63 */
viortc_ptp_get_time_fn(ktime_t * device_time,struct system_counterval_t * system_counterval,void * ctx)64 static int viortc_ptp_get_time_fn(ktime_t *device_time,
65 struct system_counterval_t *system_counterval,
66 void *ctx)
67 {
68 struct viortc_ptp_cross_ctx *vio_ctx = ctx;
69
70 *device_time = vio_ctx->device_time;
71 *system_counterval = vio_ctx->system_counterval;
72
73 return 0;
74 }
75
76 /**
77 * viortc_ptp_do_xtstamp() - get crosststamp from device
78 * @vio_ptp: virtio_rtc PTP clock
79 * @hw_counter: virtio_rtc HW counter type
80 * @cs_id: clocksource id corresponding to hw_counter
81 * @ctx: context for get_device_system_crosststamp()
82 *
83 * Reads HW-specific crosststamp from device.
84 *
85 * Context: Process context.
86 * Return: Zero on success, negative error code otherwise.
87 */
viortc_ptp_do_xtstamp(struct viortc_ptp_clock * vio_ptp,u8 hw_counter,enum clocksource_ids cs_id,struct viortc_ptp_cross_ctx * ctx)88 static int viortc_ptp_do_xtstamp(struct viortc_ptp_clock *vio_ptp,
89 u8 hw_counter, enum clocksource_ids cs_id,
90 struct viortc_ptp_cross_ctx *ctx)
91 {
92 u64 max_ns, ns;
93 int ret;
94
95 ctx->system_counterval.cs_id = cs_id;
96
97 ret = viortc_read_cross(vio_ptp->viortc, vio_ptp->vio_clk_id,
98 hw_counter, &ns,
99 &ctx->system_counterval.cycles);
100 if (ret)
101 return ret;
102
103 max_ns = (u64)ktime_to_ns(KTIME_MAX);
104 if (ns > max_ns)
105 return -EINVAL;
106
107 ctx->device_time = ns_to_ktime(ns);
108
109 return 0;
110 }
111
112 /*
113 * PTP clock operations
114 */
115
116 /**
117 * viortc_ptp_getcrosststamp() - PTP clock getcrosststamp op
118 * @ptp: PTP clock info
119 * @xtstamp: crosststamp
120 *
121 * Context: Process context.
122 * Return: Zero on success, negative error code otherwise.
123 */
viortc_ptp_getcrosststamp(struct ptp_clock_info * ptp,struct system_device_crosststamp * xtstamp)124 static int viortc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
125 struct system_device_crosststamp *xtstamp)
126 {
127 struct viortc_ptp_clock *vio_ptp =
128 container_of(ptp, struct viortc_ptp_clock, ptp_info);
129 struct system_time_snapshot history_begin;
130 struct viortc_ptp_cross_ctx ctx;
131 enum clocksource_ids cs_id;
132 u8 hw_counter;
133 int ret;
134
135 if (!vio_ptp->have_cross)
136 return -EOPNOTSUPP;
137
138 ret = viortc_hw_xtstamp_params(&hw_counter, &cs_id);
139 if (ret)
140 return ret;
141
142 ktime_get_snapshot(&history_begin);
143 if (history_begin.cs_id != cs_id)
144 return -EOPNOTSUPP;
145
146 /*
147 * Getting the timestamp can take many milliseconds with a slow Virtio
148 * device. This is too long for viortc_ptp_get_time_fn() passed to
149 * get_device_system_crosststamp(), which has to usually return before
150 * the timekeeper seqcount increases (every tick or so).
151 *
152 * So, get the actual cross-timestamp first.
153 */
154 ret = viortc_ptp_do_xtstamp(vio_ptp, hw_counter, cs_id, &ctx);
155 if (ret)
156 return ret;
157
158 ret = get_device_system_crosststamp(viortc_ptp_get_time_fn, &ctx,
159 &history_begin, xtstamp);
160 if (ret)
161 pr_debug("%s: get_device_system_crosststamp() returned %d\n",
162 __func__, ret);
163
164 return ret;
165 }
166
167 /* viortc_ptp_adjfine() - unsupported PTP clock adjfine op */
viortc_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)168 static int viortc_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
169 {
170 return -EOPNOTSUPP;
171 }
172
173 /* viortc_ptp_adjtime() - unsupported PTP clock adjtime op */
viortc_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)174 static int viortc_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
175 {
176 return -EOPNOTSUPP;
177 }
178
179 /* viortc_ptp_settime64() - unsupported PTP clock settime64 op */
viortc_ptp_settime64(struct ptp_clock_info * ptp,const struct timespec64 * ts)180 static int viortc_ptp_settime64(struct ptp_clock_info *ptp,
181 const struct timespec64 *ts)
182 {
183 return -EOPNOTSUPP;
184 }
185
186 /*
187 * viortc_ptp_gettimex64() - PTP clock gettimex64 op
188 *
189 * Context: Process context.
190 */
viortc_ptp_gettimex64(struct ptp_clock_info * ptp,struct timespec64 * ts,struct ptp_system_timestamp * sts)191 static int viortc_ptp_gettimex64(struct ptp_clock_info *ptp,
192 struct timespec64 *ts,
193 struct ptp_system_timestamp *sts)
194 {
195 struct viortc_ptp_clock *vio_ptp =
196 container_of(ptp, struct viortc_ptp_clock, ptp_info);
197 int ret;
198 u64 ns;
199
200 ptp_read_system_prets(sts);
201 ret = viortc_read(vio_ptp->viortc, vio_ptp->vio_clk_id, &ns);
202 ptp_read_system_postts(sts);
203
204 if (ret)
205 return ret;
206
207 if (ns > (u64)S64_MAX)
208 return -EINVAL;
209
210 *ts = ns_to_timespec64((s64)ns);
211
212 return 0;
213 }
214
215 /* viortc_ptp_enable() - unsupported PTP clock enable op */
viortc_ptp_enable(struct ptp_clock_info * ptp,struct ptp_clock_request * rq,int on)216 static int viortc_ptp_enable(struct ptp_clock_info *ptp,
217 struct ptp_clock_request *rq, int on)
218 {
219 return -EOPNOTSUPP;
220 }
221
222 /*
223 * viortc_ptp_info_template - ptp_clock_info template
224 *
225 * The .name member will be set for individual virtio_rtc PTP clocks.
226 *
227 * The .getcrosststamp member will be cleared for PTP clocks not supporting
228 * crosststamp.
229 */
230 static const struct ptp_clock_info viortc_ptp_info_template = {
231 .owner = THIS_MODULE,
232 /* .name is set according to clock type */
233 .adjfine = viortc_ptp_adjfine,
234 .adjtime = viortc_ptp_adjtime,
235 .gettimex64 = viortc_ptp_gettimex64,
236 .settime64 = viortc_ptp_settime64,
237 .enable = viortc_ptp_enable,
238 .getcrosststamp = viortc_ptp_getcrosststamp,
239 };
240
241 /**
242 * viortc_ptp_unregister() - PTP clock unregistering wrapper
243 * @vio_ptp: virtio_rtc PTP clock
244 * @parent_dev: parent device of PTP clock
245 *
246 * Return: Zero on success, negative error code otherwise.
247 */
viortc_ptp_unregister(struct viortc_ptp_clock * vio_ptp,struct device * parent_dev)248 int viortc_ptp_unregister(struct viortc_ptp_clock *vio_ptp,
249 struct device *parent_dev)
250 {
251 int ret = ptp_clock_unregister(vio_ptp->ptp_clock);
252
253 if (!ret)
254 devm_kfree(parent_dev, vio_ptp);
255
256 return ret;
257 }
258
259 /**
260 * viortc_ptp_get_cross_cap() - get xtstamp support info from device
261 * @viortc: virtio_rtc device data
262 * @vio_ptp: virtio_rtc PTP clock abstraction
263 *
264 * Context: Process context.
265 * Return: Zero on success, negative error code otherwise.
266 */
viortc_ptp_get_cross_cap(struct viortc_dev * viortc,struct viortc_ptp_clock * vio_ptp)267 static int viortc_ptp_get_cross_cap(struct viortc_dev *viortc,
268 struct viortc_ptp_clock *vio_ptp)
269 {
270 enum clocksource_ids cs_id;
271 bool xtstamp_supported;
272 u8 hw_counter;
273 int ret;
274
275 ret = viortc_hw_xtstamp_params(&hw_counter, &cs_id);
276 if (ret) {
277 vio_ptp->have_cross = false;
278 return 0;
279 }
280
281 ret = viortc_cross_cap(viortc, vio_ptp->vio_clk_id, hw_counter,
282 &xtstamp_supported);
283 if (ret)
284 return ret;
285
286 vio_ptp->have_cross = xtstamp_supported;
287
288 return 0;
289 }
290
291 /**
292 * viortc_ptp_register() - prepare and register PTP clock
293 * @viortc: virtio_rtc device data
294 * @parent_dev: parent device for PTP clock
295 * @vio_clk_id: id of virtio_rtc clock which backs PTP clock
296 * @ptp_clock_name: PTP clock name
297 *
298 * Context: Process context.
299 * Return: Pointer on success, ERR_PTR() otherwise; NULL if PTP clock support
300 * not available.
301 */
viortc_ptp_register(struct viortc_dev * viortc,struct device * parent_dev,u16 vio_clk_id,const char * ptp_clock_name)302 struct viortc_ptp_clock *viortc_ptp_register(struct viortc_dev *viortc,
303 struct device *parent_dev,
304 u16 vio_clk_id,
305 const char *ptp_clock_name)
306 {
307 struct viortc_ptp_clock *vio_ptp;
308 struct ptp_clock *ptp_clock;
309 ssize_t len;
310 int ret;
311
312 vio_ptp = devm_kzalloc(parent_dev, sizeof(*vio_ptp), GFP_KERNEL);
313 if (!vio_ptp)
314 return ERR_PTR(-ENOMEM);
315
316 vio_ptp->viortc = viortc;
317 vio_ptp->vio_clk_id = vio_clk_id;
318 vio_ptp->ptp_info = viortc_ptp_info_template;
319 len = strscpy(vio_ptp->ptp_info.name, ptp_clock_name,
320 sizeof(vio_ptp->ptp_info.name));
321 if (len < 0) {
322 ret = len;
323 goto err_free_dev;
324 }
325
326 ret = viortc_ptp_get_cross_cap(viortc, vio_ptp);
327 if (ret)
328 goto err_free_dev;
329
330 if (!vio_ptp->have_cross)
331 vio_ptp->ptp_info.getcrosststamp = NULL;
332
333 ptp_clock = ptp_clock_register(&vio_ptp->ptp_info, parent_dev);
334 if (IS_ERR(ptp_clock))
335 goto err_on_register;
336
337 vio_ptp->ptp_clock = ptp_clock;
338
339 return vio_ptp;
340
341 err_on_register:
342 ret = PTR_ERR(ptp_clock);
343
344 err_free_dev:
345 devm_kfree(parent_dev, vio_ptp);
346 return ERR_PTR(ret);
347 }
348