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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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