lkml.org 
[lkml]   [2019]   [May]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH v1] timer:clock:ptp: add support the dynamic posix clock alarm set for ptp
Date
Current kernel code do not support the dynamic posix clock alarm set.
This code would support it by the posix timer structure.

319 const struct k_clock clock_posix_dynamic = {

320 .clock_getres = pc_clock_getres,
321 .clock_set = pc_clock_settime,
322 .clock_get = pc_clock_gettime,
323 .clock_adj = pc_clock_adjtime,
324 + .timer_create = pc_timer_create,
325 + .timer_del = pc_timer_delete,
326 + .timer_set = pc_timer_set,
327 + .timer_arm = pc_timer_arm,
}

This won't change the user space system call code. Normally the user
space set alarm by timer_create() and timer_settime(). Reference code
are tools/testing/selftests/ptp/testptp.c.

Some case requiring providing the alarm set for user space by ptp clock.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc_ptp.c | 1 +
drivers/ptp/ptp_clock.c | 39 ++++++++++++++-
drivers/ptp/ptp_qoriq.c | 44 +++++++++++++++++
include/linux/fsl/ptp_qoriq.h | 3 ++
include/linux/posix-clock.h | 3 +-
include/linux/ptp_clock_kernel.h | 5 +-
kernel/time/posix-clock.c | 60 ++++++++++++++++++++++++
7 files changed, 152 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
index 8c1497e..35e2f2a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
@@ -21,6 +21,7 @@
.gettime64 = ptp_qoriq_gettime,
.settime64 = ptp_qoriq_settime,
.enable = ptp_qoriq_enable,
+ .alarm = ptp_qoriq_alarm,
};

static int enetc_ptp_probe(struct pci_dev *pdev,
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 79bd102..72d06a8 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -23,7 +23,9 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/sched/task.h>
#include <linux/posix-clock.h>
+#include <linux/posix-timers.h>
#include <linux/pps_kernel.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
@@ -166,12 +168,31 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx)
return err;
}

+static int ptp_clock_alarm(struct posix_clock *pc, ktime_t expires,
+ bool absolute, struct k_itimer *timr)
+{
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ struct ptp_clock_info *ops;
+
+ ops = ptp->info;
+ if (!ops)
+ return -EINVAL;
+
+ if (!ops->alarm)
+ return -EINVAL;
+
+ ops->alarm(ops, expires, absolute, timr);
+
+ return 0;
+}
+
static struct posix_clock_operations ptp_clock_ops = {
.owner = THIS_MODULE,
.clock_adjtime = ptp_clock_adjtime,
.clock_gettime = ptp_clock_gettime,
.clock_getres = ptp_clock_getres,
.clock_settime = ptp_clock_settime,
+ .clock_alarm = ptp_clock_alarm,
.ioctl = ptp_ioctl,
.open = ptp_open,
.poll = ptp_poll,
@@ -324,6 +345,20 @@ int ptp_clock_unregister(struct ptp_clock *ptp)
}
EXPORT_SYMBOL(ptp_clock_unregister);

+int alarm_timer_event(struct k_itimer *timr, int si_private)
+{
+ int ret = -1;
+
+ timr->sigq->info.si_sys_private = si_private;
+
+ rcu_read_lock();
+ ret = send_sigqueue(timr->sigq, timr->it_pid, PIDTYPE_PID);
+ rcu_read_unlock();
+
+ /* If we failed to send the signal the timer stops. */
+ return ret > 0;
+}
+
void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
{
struct pps_event_time evt;
@@ -331,8 +366,10 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
switch (event->type) {

case PTP_CLOCK_ALARM:
+ if (!event->timr)
+ break;
+ alarm_timer_event(event->timr, 0);
break;
-
case PTP_CLOCK_EXTTS:
enqueue_external_timestamp(&ptp->tsevq, event);
wake_up_interruptible(&ptp->tsev_wq);
diff --git a/drivers/ptp/ptp_qoriq.c b/drivers/ptp/ptp_qoriq.c
index 5377536..ce14d44 100644
--- a/drivers/ptp/ptp_qoriq.c
+++ b/drivers/ptp/ptp_qoriq.c
@@ -163,10 +163,15 @@ irqreturn_t ptp_qoriq_isr(int irq, void *priv)

if (irqs & ALM2) {
ack |= ALM2;
+ if (!ptp_qoriq->timr) {
+ ptp_qoriq->alarm_value = 0;
+ ptp_qoriq->alarm_interval = 0;
+ }
if (ptp_qoriq->alarm_value) {
event.type = PTP_CLOCK_ALARM;
event.index = 0;
event.timestamp = ptp_qoriq->alarm_value;
+ event.timr = ptp_qoriq->timr;
ptp_clock_event(ptp_qoriq->clock, &event);
}
if (ptp_qoriq->alarm_interval) {
@@ -341,6 +346,44 @@ int ptp_qoriq_enable(struct ptp_clock_info *ptp,
}
EXPORT_SYMBOL_GPL(ptp_qoriq_enable);

+int ptp_qoriq_alarm(struct ptp_clock_info *ptp, ktime_t expires,
+ bool absolute, struct k_itimer *timr)
+{
+ u64 ns, now;
+ u32 lo, hi, mask;
+
+ struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
+ struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
+
+ if (!timr)
+ return -EINVAL;
+
+ now = tmr_cnt_read(ptp_qoriq);
+ if (!absolute)
+ ns = now + ktime_to_ns(expires);
+ else if (ktime_to_ns(expires) < now)
+ ns = now;
+ else
+ ns = ktime_to_ns(expires);
+
+ hi = ns >> 32;
+ lo = ns & 0xffffffff;
+ ptp_qoriq->write(&regs->alarm_regs->tmr_alarm2_l, lo);
+ ptp_qoriq->write(&regs->alarm_regs->tmr_alarm2_h, hi);
+
+ spin_lock(&ptp_qoriq->lock);
+ mask = ptp_qoriq->read(&regs->ctrl_regs->tmr_temask);
+ mask |= ALM2EN;
+ ptp_qoriq->write(&regs->ctrl_regs->tmr_temask, mask);
+ spin_unlock(&ptp_qoriq->lock);
+
+ ptp_qoriq->alarm_value = ns;
+ ptp_qoriq->alarm_interval = ktime_to_ns(timr->it_interval);
+
+ ptp_qoriq->timr = timr;
+ return 0;
+}
+
static const struct ptp_clock_info ptp_qoriq_caps = {
.owner = THIS_MODULE,
.name = "qoriq ptp clock",
@@ -355,6 +398,7 @@ int ptp_qoriq_enable(struct ptp_clock_info *ptp,
.gettime64 = ptp_qoriq_gettime,
.settime64 = ptp_qoriq_settime,
.enable = ptp_qoriq_enable,
+ .alarm = ptp_qoriq_alarm,
};

/**
diff --git a/include/linux/fsl/ptp_qoriq.h b/include/linux/fsl/ptp_qoriq.h
index 992bf9f..2928df4 100644
--- a/include/linux/fsl/ptp_qoriq.h
+++ b/include/linux/fsl/ptp_qoriq.h
@@ -143,6 +143,7 @@ struct ptp_qoriq {
spinlock_t lock; /* protects regs */
struct ptp_clock *clock;
struct ptp_clock_info caps;
+ struct k_itimer *timr;
struct resource *rsrc;
struct dentry *debugfs_root;
struct device *dev;
@@ -190,6 +191,8 @@ int ptp_qoriq_init(struct ptp_qoriq *ptp_qoriq, void __iomem *base,
int ptp_qoriq_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts);
int ptp_qoriq_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts);
+int ptp_qoriq_alarm(struct ptp_clock_info *ptp, ktime_t expires,
+ bool absolute, struct k_itimer *timr);
int ptp_qoriq_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on);
#ifdef CONFIG_DEBUG_FS
diff --git a/include/linux/posix-clock.h b/include/linux/posix-clock.h
index 18674d7..80cc214 100644
--- a/include/linux/posix-clock.h
+++ b/include/linux/posix-clock.h
@@ -59,7 +59,8 @@ struct posix_clock_operations {

int (*clock_settime)(struct posix_clock *pc,
const struct timespec64 *ts);
-
+ int (*clock_alarm)(struct posix_clock *pc, ktime_t expires,
+ bool absolute, struct k_itimer *timr);
/*
* Optional character device methods:
*/
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
index 7121bbe..b51f64b 100644
--- a/include/linux/ptp_clock_kernel.h
+++ b/include/linux/ptp_clock_kernel.h
@@ -24,7 +24,7 @@
#include <linux/device.h>
#include <linux/pps_kernel.h>
#include <linux/ptp_clock.h>
-
+#include <linux/posix-timers.h>

struct ptp_clock_request {
enum {
@@ -148,6 +148,8 @@ struct ptp_clock_info {
int (*getcrosststamp)(struct ptp_clock_info *ptp,
struct system_device_crosststamp *cts);
int (*settime64)(struct ptp_clock_info *p, const struct timespec64 *ts);
+ int (*alarm)(struct ptp_clock_info *p, ktime_t expires,
+ bool absolute, struct k_itimer *timr);
int (*enable)(struct ptp_clock_info *ptp,
struct ptp_clock_request *request, int on);
int (*verify)(struct ptp_clock_info *ptp, unsigned int pin,
@@ -180,6 +182,7 @@ struct ptp_clock_event {
u64 timestamp;
struct pps_event_time pps_times;
};
+ struct k_itimer *timr;
};

#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
index ec960bb..ac25d17 100644
--- a/kernel/time/posix-clock.c
+++ b/kernel/time/posix-clock.c
@@ -8,6 +8,7 @@
#include <linux/export.h>
#include <linux/file.h>
#include <linux/posix-clock.h>
+#include <linux/posix-timers.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
@@ -314,9 +315,68 @@ static int pc_clock_settime(clockid_t id, const struct timespec64 *ts)
return err;
}

+static void pc_timer_arm(struct k_itimer *timr, ktime_t expires,
+ bool absolute, bool sigev_none)
+{
+ struct posix_clock_desc cd;
+ int err;
+
+ err = get_clock_desc(timr->it_clock, &cd);
+ if (err)
+ return;
+
+ cd.clk->ops.clock_alarm(cd.clk, expires, absolute, timr);
+}
+
+static int pc_timer_set(struct k_itimer *timr, int flags,
+ struct itimerspec64 *new_setting,
+ struct itimerspec64 *old_setting)
+{
+ const struct k_clock *kc = timr->kclock;
+ bool sigev_none;
+ ktime_t expires;
+
+ if (old_setting)
+ pr_err("old_setting not support!\n");
+
+ /* Prevent rearming by clearing the interval */
+ timr->it_interval = 0;
+
+ timr->it_active = 0;
+ timr->it_requeue_pending = (timr->it_requeue_pending + 2) &
+ ~REQUEUE_PENDING;
+ timr->it_overrun_last = 0;
+
+ /* Switch off the timer when it_value is zero */
+ if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec)
+ return 0;
+
+ timr->it_interval = timespec64_to_ktime(new_setting->it_interval);
+ expires = timespec64_to_ktime(new_setting->it_value);
+ sigev_none = timr->it_sigev_notify == SIGEV_NONE;
+
+ kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none);
+ timr->it_active = !sigev_none;
+ return 0;
+}
+
+static int pc_timer_create(struct k_itimer *new_timer)
+{
+ return 0;
+}
+
+static int pc_timer_delete(struct k_itimer *new_timer)
+{
+ return 0;
+}
+
const struct k_clock clock_posix_dynamic = {
.clock_getres = pc_clock_getres,
.clock_set = pc_clock_settime,
.clock_get = pc_clock_gettime,
.clock_adj = pc_clock_adjtime,
+ .timer_create = pc_timer_create,
+ .timer_del = pc_timer_delete,
+ .timer_set = pc_timer_set,
+ .timer_arm = pc_timer_arm,
};
--
1.8.3.1
\
 
 \ /
  Last update: 2019-05-05 07:03    [W:0.131 / U:0.416 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site