xref: /linux/drivers/virtio/virtio_rtc_ptp.c (revision 8ca154e4910efff1b04e7750e007d75732c68323)
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