Skip to content

Commit 3618008

Browse files
mlichvardavem330
authored andcommitted
ptp: add PTP_SYS_OFFSET_EXTENDED ioctl
The PTP_SYS_OFFSET ioctl, which can be used to measure the offset between a PHC and the system clock, includes the total time that the driver needs to read the PHC timestamp. This typically involves reading of multiple PCI registers (sometimes in multiple iterations) and the register that contains the lowest bits of the timestamp is not read in the middle between the two readings of the system clock. This asymmetry causes the measured offset to have a significant error. Introduce a new ioctl, driver function, and helper functions, which allow the reading of the lowest register to be isolated from the other readings in order to reduce the asymmetry. The ioctl returns three timestamps for each measurement: - system time right before reading the lowest bits of the PHC timestamp - PHC time - system time immediately after reading the lowest bits of the PHC timestamp Cc: Richard Cochran <richardcochran@gmail.com> Cc: Jacob Keller <jacob.e.keller@intel.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 83d0bdc commit 3618008

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

drivers/ptp/ptp_chardev.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,12 @@ int ptp_open(struct posix_clock *pc, fmode_t fmode)
122122
long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
123123
{
124124
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
125+
struct ptp_sys_offset_extended *extoff = NULL;
125126
struct ptp_sys_offset_precise precise_offset;
126127
struct system_device_crosststamp xtstamp;
127128
struct ptp_clock_info *ops = ptp->info;
128129
struct ptp_sys_offset *sysoff = NULL;
130+
struct ptp_system_timestamp sts;
129131
struct ptp_clock_request req;
130132
struct ptp_clock_caps caps;
131133
struct ptp_clock_time *pct;
@@ -211,6 +213,36 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
211213
err = -EFAULT;
212214
break;
213215

216+
case PTP_SYS_OFFSET_EXTENDED:
217+
if (!ptp->info->gettimex64) {
218+
err = -EOPNOTSUPP;
219+
break;
220+
}
221+
extoff = memdup_user((void __user *)arg, sizeof(*extoff));
222+
if (IS_ERR(extoff)) {
223+
err = PTR_ERR(extoff);
224+
extoff = NULL;
225+
break;
226+
}
227+
if (extoff->n_samples > PTP_MAX_SAMPLES) {
228+
err = -EINVAL;
229+
break;
230+
}
231+
for (i = 0; i < extoff->n_samples; i++) {
232+
err = ptp->info->gettimex64(ptp->info, &ts, &sts);
233+
if (err)
234+
goto out;
235+
extoff->ts[i][0].sec = sts.pre_ts.tv_sec;
236+
extoff->ts[i][0].nsec = sts.pre_ts.tv_nsec;
237+
extoff->ts[i][1].sec = ts.tv_sec;
238+
extoff->ts[i][1].nsec = ts.tv_nsec;
239+
extoff->ts[i][2].sec = sts.post_ts.tv_sec;
240+
extoff->ts[i][2].nsec = sts.post_ts.tv_nsec;
241+
}
242+
if (copy_to_user((void __user *)arg, extoff, sizeof(*extoff)))
243+
err = -EFAULT;
244+
break;
245+
214246
case PTP_SYS_OFFSET:
215247
sysoff = memdup_user((void __user *)arg, sizeof(*sysoff));
216248
if (IS_ERR(sysoff)) {
@@ -284,6 +316,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
284316
}
285317

286318
out:
319+
kfree(extoff);
287320
kfree(sysoff);
288321
return err;
289322
}

include/linux/ptp_clock_kernel.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ struct ptp_clock_request {
3939
};
4040

4141
struct system_device_crosststamp;
42+
43+
/**
44+
* struct ptp_system_timestamp - system time corresponding to a PHC timestamp
45+
*/
46+
struct ptp_system_timestamp {
47+
struct timespec64 pre_ts;
48+
struct timespec64 post_ts;
49+
};
50+
4251
/**
4352
* struct ptp_clock_info - decribes a PTP hardware clock
4453
*
@@ -75,6 +84,14 @@ struct system_device_crosststamp;
7584
* @gettime64: Reads the current time from the hardware clock.
7685
* parameter ts: Holds the result.
7786
*
87+
* @gettimex64: Reads the current time from the hardware clock and optionally
88+
* also the system clock.
89+
* parameter ts: Holds the PHC timestamp.
90+
* parameter sts: If not NULL, it holds a pair of timestamps from
91+
* the system clock. The first reading is made right before
92+
* reading the lowest bits of the PHC timestamp and the second
93+
* reading immediately follows that.
94+
*
7895
* @getcrosststamp: Reads the current time from the hardware clock and
7996
* system clock simultaneously.
8097
* parameter cts: Contains timestamp (device,system) pair,
@@ -124,6 +141,8 @@ struct ptp_clock_info {
124141
int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
125142
int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
126143
int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts);
144+
int (*gettimex64)(struct ptp_clock_info *ptp, struct timespec64 *ts,
145+
struct ptp_system_timestamp *sts);
127146
int (*getcrosststamp)(struct ptp_clock_info *ptp,
128147
struct system_device_crosststamp *cts);
129148
int (*settime64)(struct ptp_clock_info *p, const struct timespec64 *ts);
@@ -247,4 +266,16 @@ static inline int ptp_schedule_worker(struct ptp_clock *ptp,
247266

248267
#endif
249268

269+
static inline void ptp_read_system_prets(struct ptp_system_timestamp *sts)
270+
{
271+
if (sts)
272+
ktime_get_real_ts64(&sts->pre_ts);
273+
}
274+
275+
static inline void ptp_read_system_postts(struct ptp_system_timestamp *sts)
276+
{
277+
if (sts)
278+
ktime_get_real_ts64(&sts->post_ts);
279+
}
280+
250281
#endif

include/uapi/linux/ptp_clock.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@ struct ptp_sys_offset {
8484
struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1];
8585
};
8686

87+
struct ptp_sys_offset_extended {
88+
unsigned int n_samples; /* Desired number of measurements. */
89+
unsigned int rsv[3]; /* Reserved for future use. */
90+
/*
91+
* Array of [system, phc, system] time stamps. The kernel will provide
92+
* 3*n_samples time stamps.
93+
*/
94+
struct ptp_clock_time ts[PTP_MAX_SAMPLES][3];
95+
};
96+
8797
struct ptp_sys_offset_precise {
8898
struct ptp_clock_time device;
8999
struct ptp_clock_time sys_realtime;
@@ -136,6 +146,8 @@ struct ptp_pin_desc {
136146
#define PTP_PIN_SETFUNC _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc)
137147
#define PTP_SYS_OFFSET_PRECISE \
138148
_IOWR(PTP_CLK_MAGIC, 8, struct ptp_sys_offset_precise)
149+
#define PTP_SYS_OFFSET_EXTENDED \
150+
_IOW(PTP_CLK_MAGIC, 9, struct ptp_sys_offset_extended)
139151

140152
struct ptp_extts_event {
141153
struct ptp_clock_time t; /* Time event occured. */

0 commit comments

Comments
 (0)