[PATCH v1] timer:clock:ptp: add support the dynamic posix clock alarm set for ptp

Po Liu po.liu at nxp.com
Sun May 5 15:02:05 AEST 2019


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 at 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



More information about the Linuxppc-dev mailing list