aboutsummaryrefslogtreecommitdiff
path: root/drivers/ptp
diff options
context:
space:
mode:
authorGerhard Engleder2022-05-06 22:01:37 +0200
committerPaolo Abeni2022-05-10 09:48:08 +0200
commit42704b26b0f1d891f6cf4ebc877dbac0d17c690d (patch)
tree283ba260e6ab1b1add2628846ae4cabd657e12ed /drivers/ptp
parentb3552d6a3b8bd4260a971f1f70140ed3513cc4f7 (diff)
ptp: Add cycles support for virtual clocks
ptp vclocks require a free running time for their timecounter. Currently only a physical clock forced to free running is supported. If vclocks are used, then the physical clock cannot be synchronized anymore. The synchronized time is not available in hardware in this case. As a result, timed transmission with TAPRIO hardware support is not possible anymore. If hardware would support a free running time additionally to the physical clock, then the physical clock does not need to be forced to free running. Thus, the physical clocks can still be synchronized while vclocks are in use. The physical clock could be used to synchronize the time domain of the TSN network and trigger TAPRIO. In parallel vclocks can be used to synchronize other time domains. Introduce support for a free running cycle counter called cycles to physical clocks. Rework ptp vclocks to use this free running cycle counter. Default implementation is based on time of physical clock. Thus, behavior of ptp vclocks based on physical clocks without free running cycle counter is identical to previous behavior. Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'drivers/ptp')
-rw-r--r--drivers/ptp/ptp_clock.c31
-rw-r--r--drivers/ptp/ptp_private.h10
-rw-r--r--drivers/ptp/ptp_sysfs.c11
-rw-r--r--drivers/ptp/ptp_vclock.c13
4 files changed, 49 insertions, 16 deletions
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index b6f2cfd15dd2..688cde320bb0 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -77,8 +77,8 @@ static int ptp_clock_settime(struct posix_clock *pc, const struct timespec64 *tp
{
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
- if (ptp_vclock_in_use(ptp)) {
- pr_err("ptp: virtual clock in use\n");
+ if (ptp_clock_freerun(ptp)) {
+ pr_err("ptp: physical clock is free running\n");
return -EBUSY;
}
@@ -103,8 +103,8 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx)
struct ptp_clock_info *ops;
int err = -EOPNOTSUPP;
- if (ptp_vclock_in_use(ptp)) {
- pr_err("ptp: virtual clock in use\n");
+ if (ptp_clock_freerun(ptp)) {
+ pr_err("ptp: physical clock is free running\n");
return -EBUSY;
}
@@ -178,6 +178,14 @@ static void ptp_clock_release(struct device *dev)
kfree(ptp);
}
+static int ptp_getcycles64(struct ptp_clock_info *info, struct timespec64 *ts)
+{
+ if (info->getcyclesx64)
+ return info->getcyclesx64(info, ts, NULL);
+ else
+ return info->gettime64(info, ts);
+}
+
static void ptp_aux_kworker(struct kthread_work *work)
{
struct ptp_clock *ptp = container_of(work, struct ptp_clock,
@@ -225,6 +233,21 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
mutex_init(&ptp->n_vclocks_mux);
init_waitqueue_head(&ptp->tsev_wq);
+ if (ptp->info->getcycles64 || ptp->info->getcyclesx64) {
+ ptp->has_cycles = true;
+ if (!ptp->info->getcycles64 && ptp->info->getcyclesx64)
+ ptp->info->getcycles64 = ptp_getcycles64;
+ } else {
+ /* Free running cycle counter not supported, use time. */
+ ptp->info->getcycles64 = ptp_getcycles64;
+
+ if (ptp->info->gettimex64)
+ ptp->info->getcyclesx64 = ptp->info->gettimex64;
+
+ if (ptp->info->getcrosststamp)
+ ptp->info->getcrosscycles = ptp->info->getcrosststamp;
+ }
+
if (ptp->info->do_aux_work) {
kthread_init_delayed_work(&ptp->aux_work, ptp_aux_kworker);
ptp->kworker = kthread_create_worker(0, "ptp%d", ptp->index);
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index dba6be477067..ab47c10b3874 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -52,6 +52,7 @@ struct ptp_clock {
int *vclock_index;
struct mutex n_vclocks_mux; /* protect concurrent n_vclocks access */
bool is_virtual_clock;
+ bool has_cycles;
};
#define info_to_vclock(d) container_of((d), struct ptp_vclock, info)
@@ -96,6 +97,15 @@ static inline bool ptp_vclock_in_use(struct ptp_clock *ptp)
return in_use;
}
+/* Check if ptp clock shall be free running */
+static inline bool ptp_clock_freerun(struct ptp_clock *ptp)
+{
+ if (ptp->has_cycles)
+ return false;
+
+ return ptp_vclock_in_use(ptp);
+}
+
extern struct class *ptp_class;
/*
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index 9233bfedeb17..f30b0a439470 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -231,10 +231,13 @@ static ssize_t n_vclocks_store(struct device *dev,
*(ptp->vclock_index + ptp->n_vclocks - i) = -1;
}
- if (num == 0)
- dev_info(dev, "only physical clock in use now\n");
- else
- dev_info(dev, "guarantee physical clock free running\n");
+ /* Need to inform about changed physical clock behavior */
+ if (!ptp->has_cycles) {
+ if (num == 0)
+ dev_info(dev, "only physical clock in use now\n");
+ else
+ dev_info(dev, "guarantee physical clock free running\n");
+ }
ptp->n_vclocks = num;
mutex_unlock(&ptp->n_vclocks_mux);
diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c
index cb179a3ea508..3a095eab9cc5 100644
--- a/drivers/ptp/ptp_vclock.c
+++ b/drivers/ptp/ptp_vclock.c
@@ -68,7 +68,7 @@ static int ptp_vclock_gettimex(struct ptp_clock_info *ptp,
int err;
u64 ns;
- err = pptp->info->gettimex64(pptp->info, &pts, sts);
+ err = pptp->info->getcyclesx64(pptp->info, &pts, sts);
if (err)
return err;
@@ -104,7 +104,7 @@ static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp,
int err;
u64 ns;
- err = pptp->info->getcrosststamp(pptp->info, xtstamp);
+ err = pptp->info->getcrosscycles(pptp->info, xtstamp);
if (err)
return err;
@@ -143,10 +143,7 @@ static u64 ptp_vclock_read(const struct cyclecounter *cc)
struct ptp_clock *ptp = vclock->pclock;
struct timespec64 ts = {};
- if (ptp->info->gettimex64)
- ptp->info->gettimex64(ptp->info, &ts, NULL);
- else
- ptp->info->gettime64(ptp->info, &ts);
+ ptp->info->getcycles64(ptp->info, &ts);
return timespec64_to_ns(&ts);
}
@@ -168,11 +165,11 @@ struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock)
vclock->pclock = pclock;
vclock->info = ptp_vclock_info;
- if (pclock->info->gettimex64)
+ if (pclock->info->getcyclesx64)
vclock->info.gettimex64 = ptp_vclock_gettimex;
else
vclock->info.gettime64 = ptp_vclock_gettime;
- if (pclock->info->getcrosststamp)
+ if (pclock->info->getcrosscycles)
vclock->info.getcrosststamp = ptp_vclock_getcrosststamp;
vclock->cc = ptp_vclock_cc;