Re: [PATCHv3 13/16] pps: capture MONOTONIC_RAW timestamps as well

Previous thread: [PATCHv3 05/16] pps: access pps device by direct pointer by Alexander Gordeev on Wednesday, August 4, 2010 - 2:06 pm. (6 messages)

Next thread: [PATCH 2/3] perf: expose event__process function by Arnaldo Carvalho de Melo on Wednesday, August 4, 2010 - 2:26 pm. (1 message)
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

This patchset contains several changes that improve an overall
design/performance of PPS subsystem. I'd like these patches to be
merged mainline if no one objects.

Patches 1-3 are bugfixes.
Patches 4-11 are other improvements to PPS subsystem.
Patches 12-14 add kernel consumer support.
Patch 15 adds parallel port PPS client.
Patch 16 adds parallel port PPS generator.

You can find description for my previous patchset (it describes patches
12-16 in more detailed) here: http://lkml.org/lkml/2010/2/24/189

This patchset is tested against the vanilla 2.6.35 kernel. But we are
actually using it on 2.6.33.7-rt29 rt-preempt kernel most of the time.
Those who are interested in other versions of the patchset can find
them in my git repository:
git://github.com/ago/linux-2.6.git

There is one problem however: kernel consumer works bad (if enabled)
when CONFIG_NO_HZ is enabled. The reason for this is commit
a092ff0f90cae22b2ac8028ecd2c6f6c1a9e4601. Without it hardpps() is able
to sync to 1us precision in about 10 seconds. With CONFIG_NO_HZ it is
not syncing at all. This only affects patches 12-14, others are ok.

2John Stultz: the problem is not with logarithmic accumulation because
it works good if NTP_INTERVAL_FREQ is set to 2.

Changelog
v2 -> v3:
 * add patches 1-11
 * add clear_wait parameter to pps_parport
 * add delay parameter to pps_gen_parport
 * fix seqlock unlocking
 * fix issues pointed out by Rodolfo Giometti:
   * move CONFIG_NTP_PPS to drivers/pps/Kconfig
   * swap parport client and generator patches
   * style and typo fixes
 * move patch that adds unified timestamp gathering to be the beginning

v1 -> v2:
 * fix issues pointed out by John Stultz:
   * style fixes
   * add a about the authorship of the original code
   * replace timespec with pps_normtime struct where timespec is used
     in a wrong way
   * fix seqlock usage in hardpps()
 * unbind kernel consumer on device removal
 * send raw timestamp instead of the last difference to hardpps() ...
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Since we now have direct pointers to struct pps_device everywhere it's
easy to use dev_* functions to print messages instead of plain printks.
Where dev_* cannot be used printks are converted to pr_*.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/clients/pps-ktimer.c |    4 ++--
 drivers/pps/kapi.c               |   14 +++++++-------
 drivers/pps/pps.c                |   24 ++++++++++++------------
 3 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
index 64cba1d..9d27239 100644
--- a/drivers/pps/clients/pps-ktimer.c
+++ b/drivers/pps/clients/pps-ktimer.c
@@ -45,7 +45,7 @@ static void pps_ktimer_event(unsigned long ptr)
 	/* First of all we get the time stamp... */
 	pps_get_ts(&ts);
 
-	pr_info("PPS event at %lu\n", jiffies);
+	dev_info(pps->dev, "PPS event at %lu\n", jiffies);
 
 	pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
 
@@ -94,7 +94,7 @@ static int __init pps_ktimer_init(void)
 	pps = pps_register_source(&pps_ktimer_info,
 				PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
 	if (pps == NULL) {
-		printk(KERN_ERR "cannot register ktimer source\n");
+		pr_err("cannot register ktimer source\n");
 		return -ENOMEM;
 	}
 
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 568223b..eddf41e 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -80,20 +80,20 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
 
 	/* Sanity checks */
 	if ((info->mode & default_params) != default_params) {
-		printk(KERN_ERR "pps: %s: unsupported default parameters\n",
+		pr_err("pps: %s: unsupported default parameters\n",
 					info->name);
 		err = -EINVAL;
 		goto pps_register_source_exit;
 	}
 	if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
 			info->echo == NULL) {
-		printk(KERN_ERR "pps: %s: echo function is not defined\n",
+		pr_err("pps: %s: echo function is not defined\n",
 					info->name);
 		err = -EINVAL;
 ...
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Add a helper function to gather timestamps. This way clients don't have
to duplicate it.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/clients/pps-ktimer.c |    9 ++-------
 drivers/pps/clients/pps-ldisc.c  |   18 ++++++------------
 drivers/pps/kapi.c               |   19 ++++++++++++-------
 include/linux/pps_kernel.h       |   19 ++++++++++++++++++-
 include/linux/serial_core.h      |    5 +++--
 include/linux/tty_ldisc.h        |    5 +++--
 6 files changed, 44 insertions(+), 31 deletions(-)

diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
index e7ef5b8..e1bdd8b 100644
--- a/drivers/pps/clients/pps-ktimer.c
+++ b/drivers/pps/clients/pps-ktimer.c
@@ -40,18 +40,13 @@ static struct timer_list ktimer;
 
 static void pps_ktimer_event(unsigned long ptr)
 {
-	struct timespec __ts;
-	struct pps_ktime ts;
+	struct pps_event_time ts;
 
 	/* First of all we get the time stamp... */
-	getnstimeofday(&__ts);
+	pps_get_ts(&ts);
 
 	pr_info("PPS event at %lu\n", jiffies);
 
-	/* ... and translate it to PPS time data struct */
-	ts.sec = __ts.tv_sec;
-	ts.nsec = __ts.tv_nsec;
-
 	pps_event(source, &ts, PPS_CAPTUREASSERT, NULL);
 
 	mod_timer(&ktimer, jiffies + HZ);
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index 8e1932d..20fc9f7 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -27,26 +27,20 @@
 #define PPS_TTY_MAGIC		0x0001
 
 static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
-				struct timespec *ts)
+				struct pps_event_time *ts)
 {
 	int id = (long)tty->disc_data;
-	struct timespec __ts;
-	struct pps_ktime pps_ts;
+	struct pps_event_time __ts;
 
 	/* First of all we get the time stamp... */
-	getnstimeofday(&__ts);
+	pps_get_ts(&__ts);
 
 	/* Does caller give us a timestamp? */
-	if (ts) {	/* Yes. Let's use it! */
-		pps_ts.sec = ts->tv_sec;
-		pps_ts.nsec = ts->tv_nsec;
-	} else {	/* No. Do it ...
From: Rodolfo Giometti
Date: Thursday, August 5, 2010 - 2:17 am

Acked-by: Rodolfo Giometti <giometti@linux.it>

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it
--

From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Here are some very trivial fixes combined:
 * add macro definitions to protect header file from including several times
 * remove declaration for an unexistent array
 * fix typos

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/kapi.c         |    2 +-
 include/linux/pps_kernel.h |    7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 1aa02db..55f3961 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -324,7 +324,7 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data)
 		captured = ~0;
 	}
 
-	/* Wake up iif captured somthing */
+	/* Wake up if captured something */
 	if (captured) {
 		pps->go = ~0;
 		wake_up_interruptible(&pps->queue);
diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
index e0a193f..c930d11 100644
--- a/include/linux/pps_kernel.h
+++ b/include/linux/pps_kernel.h
@@ -18,6 +18,9 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#ifndef LINUX_PPS_KERNEL_H
+#define LINUX_PPS_KERNEL_H
+
 #include <linux/pps.h>
 
 #include <linux/cdev.h>
@@ -71,7 +74,6 @@ struct pps_device {
 
 extern spinlock_t pps_idr_lock;
 extern struct idr pps_idr;
-extern struct timespec pps_irq_ts[];
 
 extern struct device_attribute pps_attrs[];
 
@@ -87,3 +89,6 @@ extern void pps_unregister_source(int source);
 extern int pps_register_cdev(struct pps_device *pps);
 extern void pps_unregister_cdev(struct pps_device *pps);
 extern void pps_event(int source, struct pps_ktime *ts, int event, void *data);
+
+#endif /* LINUX_PPS_KERNEL_H */
+
-- 
1.7.1

--

From: Rodolfo Giometti
Date: Thursday, August 5, 2010 - 1:57 am

Acked-by: Rodolfo Giometti <giometti@linux.it>

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it
--

From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

There was a race in PPS_FETCH ioctl handler when several processes want
to obtain PPS data simultaneously using sleeping PPS_FETCH. They all
sleep most of the time in the system call.
With the old approach when the first process waiting on the pps queue
is waken up it makes new system call right away and zeroes pps->go. So
other processes continue to sleep. This is a clear race condition
because of the global 'go' variable.
With the new approach pps->last_ev holds some value increasing at each
PPS event. PPS_FETCH ioctl handler saves current value to the local
variable at the very beginning so it can safely check that there is a
new event by just comparing both variables.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/kapi.c         |    4 ++--
 drivers/pps/pps.c          |   10 +++++++---
 include/linux/pps_kernel.h |    2 +-
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 55f3961..3f89f5e 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -326,8 +326,8 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data)
 
 	/* Wake up if captured something */
 	if (captured) {
-		pps->go = ~0;
-		wake_up_interruptible(&pps->queue);
+		pps->last_ev++;
+		wake_up_interruptible_all(&pps->queue);
 
 		kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
 	}
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index c76afb9..cb24147 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -136,6 +136,7 @@ static long pps_cdev_ioctl(struct file *file,
 
 	case PPS_FETCH: {
 		struct pps_fdata fdata;
+		unsigned int ev;
 
 		pr_debug("PPS_FETCH: source %d\n", pps->id);
 
@@ -143,11 +144,12 @@ static long pps_cdev_ioctl(struct file *file,
 		if (err)
 			return -EFAULT;
 
-		pps->go = 0;
+		ev = pps->last_ev;
 
 		/* Manage the timeout */
 		if (fdata.timeout.flags & PPS_TIME_INVALID)
-			err = wait_event_interruptible(pps->queue, pps->go);
+			err = ...
From: Vitezslav Samel
Date: Wednesday, August 4, 2010 - 10:19 pm

What happens if pps->last_ev overflows? Seems to me it would freeze
pps.

	Cheers,
		Vita
--

From: Alexander Gordeev
Date: Thursday, August 5, 2010 - 3:19 am

Hi Vitezslav,

В Thu, 5 Aug 2010 07:19:29 +0200

Yes, it will freeze the fds (if they don't use timeouts). But in normal
circumstances, i.e. when pps_event is called twice a second, it will
overflow after ~68 years of uninterrupted work. Well, it's the same
kind of problem as an overflow of struct timespec. I thought it's not
actually a problem. Should I use u64 instead of unsigned int or add a
runtime check somewhere?

-- 
  Alexander
From: Vitezslav Samel
Date: Thursday, August 5, 2010 - 4:07 am

If we're using 1PPS it's ~68 years, but someone is trying 5PPS now
(it would overflow in ~13.6 years) - what if someone tries e.g. 100PPS?
It's not the same as overflow of struct timespec! I think it deserves
some treatment.

	Cheers,
		Vita
--

From: Alexander Gordeev
Date: Thursday, August 5, 2010 - 7:31 am

В Thu, 5 Aug 2010 13:07:50 +0200

You are right. :)
I'll use u64 here then which should be enough for sure, ok?

Thanks for the note!

-- 
  Alexander
From: Rodolfo Giometti
Date: Thursday, August 5, 2010 - 2:15 am

Yes. It was added when we passed from ioctl to unlocked_ioctl...

Acked-by: Rodolfo Giometti <giometti@linux.it>

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it
--

From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Bitwise conjunction is distributive so we can simplify some conditions.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/kapi.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 220ab08..0335b2c 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -180,8 +180,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
 
 	/* Check the event */
 	pps->current_mode = pps->params.mode;
-	if ((event & PPS_CAPTUREASSERT) &
-			(pps->params.mode & PPS_CAPTUREASSERT)) {
+	if (event & pps->params.mode & PPS_CAPTUREASSERT) {
 		/* We have to add an offset? */
 		if (pps->params.mode & PPS_OFFSETASSERT)
 			pps_add_offset(&ts_real,
@@ -195,8 +194,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
 
 		captured = ~0;
 	}
-	if ((event & PPS_CAPTURECLEAR) &
-			(pps->params.mode & PPS_CAPTURECLEAR)) {
+	if (event & pps->params.mode & PPS_CAPTURECLEAR) {
 		/* We have to add an offset? */
 		if (pps->params.mode & PPS_OFFSETCLEAR)
 			pps_add_offset(&ts_real,
-- 
1.7.1

--

From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Since now idr is only used to manage char device id's and not used in
kernel API anymore it should be moved to pps.c. This also makes it
possible to release id only at actual device freeing so nobody can
register a pps device with the same id while our device is not freed
yet.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/kapi.c |   53 +---------------------------------------------------
 drivers/pps/pps.c  |   51 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 50 insertions(+), 54 deletions(-)

diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index eddf41e..041c27e 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -26,19 +26,11 @@
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/spinlock.h>
-#include <linux/idr.h>
 #include <linux/fs.h>
 #include <linux/pps_kernel.h>
 #include <linux/slab.h>
 
 /*
- * Local variables
- */
-
-static DEFINE_SPINLOCK(pps_idr_lock);
-static DEFINE_IDR(pps_idr);
-
-/*
  * Local functions
  */
 
@@ -75,7 +67,6 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
 		int default_params)
 {
 	struct pps_device *pps;
-	int id;
 	int err;
 
 	/* Sanity checks */
@@ -116,54 +107,18 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
 	init_waitqueue_head(&pps->queue);
 	spin_lock_init(&pps->lock);
 
-	/* Get new ID for the new PPS source */
-	if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
-		err = -ENOMEM;
-		goto kfree_pps;
-	}
-
-	spin_lock_irq(&pps_idr_lock);
-
-	/* Now really allocate the PPS source.
-	 * After idr_get_new() calling the new source will be freely available
-	 * into the kernel.
-	 */
-	err = idr_get_new(&pps_idr, pps, &id);
-	if (err < 0) {
-		spin_unlock_irq(&pps_idr_lock);
-		goto kfree_pps;
-	}
-
-	id = id & MAX_ID_MASK;
-	if (id >= PPS_MAX_SOURCES) {
-		spin_unlock_irq(&pps_idr_lock);
-
-		pr_err("pps: %s: too many PPS sources in the system\n",
-					info->name);
-		err = ...
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

MONOTONIC_RAW clock timestamps are ideally suited for frequency
calculation and also fit well into the original NTP hardpps design. Now
phase and frequency can be adjusted separately: the former based on
REALTIME clock and the latter based on MONOTONIC_RAW clock.
A new function getnstime_raw_and_real is added to timekeeping subsystem
to capture both timestamps at the same time and atomically.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 include/linux/pps_kernel.h |    3 ++-
 include/linux/time.h       |    2 ++
 kernel/time/timekeeping.c  |   34 ++++++++++++++++++++++++++++++++++
 3 files changed, 38 insertions(+), 1 deletions(-)

diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
index 5af0498..39fc712 100644
--- a/include/linux/pps_kernel.h
+++ b/include/linux/pps_kernel.h
@@ -48,6 +48,7 @@ struct pps_source_info {
 };
 
 struct pps_event_time {
+	struct timespec ts_raw;
 	struct timespec ts_real;
 };
 
@@ -111,7 +112,7 @@ static inline void timespec_to_pps_ktime(struct pps_ktime *kt,
 
 static inline void pps_get_ts(struct pps_event_time *ts)
 {
-	getnstimeofday(&ts->ts_real);
+	getnstime_raw_and_real(&ts->ts_raw, &ts->ts_real);
 }
 
 #endif /* LINUX_PPS_KERNEL_H */
diff --git a/include/linux/time.h b/include/linux/time.h
index ea3559f..1da8a7b 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -143,6 +143,8 @@ extern unsigned int alarm_setitimer(unsigned int seconds);
 extern int do_getitimer(int which, struct itimerval *value);
 extern void getnstimeofday(struct timespec *tv);
 extern void getrawmonotonic(struct timespec *ts);
+extern void getnstime_raw_and_real(struct timespec *ts_raw,
+		struct timespec *ts_real);
 extern void getboottime(struct timespec *ts);
 extern void monotonic_to_bootbased(struct timespec *ts);
 
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index caf8d4d..ef37b14 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -286,6 +286,40 @@ void ...
From: john stultz
Date: Wednesday, August 4, 2010 - 4:03 pm

Hmm. So this brings up an interesting point. If the system is an one
which uses arch_gettimeoffset() (which means it doesn't have
clocksources), I'm not sure if this function would return what you'd
expect.

The issue is that jiffies is the basic clocksource that is in use on
these systems, but the arch_gettimeoffset() function returns an
inter-tick time value (usually by reading the interrupt generating
decrementer or whatnot). So in this case, you'd get a
CLOCK_MONOTONIC_RAW time that is based off the raw jiffies value at the
last tick, and CLOCK_REALTIME time value at the exact time of the call.

That offset between the two would then vary depending on when in the
inter-tick period the call was made.


The two solutions would be:
1) Add the arch_gettimeoffset() value to nsecs_raw as well. Should be
safe, as any freq variance from the raw freq will be limited to 1 tick
length and won't accumulate.

2) Don't add arch_gettimeoffset to either value, providing the raw and
real time values at the last tick.

I'd probably go with #1.

Otherwise, the code looks good.

thanks
-john


--

From: Alexander Gordeev
Date: Thursday, August 5, 2010 - 5:16 am

В Wed, 04 Aug 2010 16:03:57 -0700

Ok, thanks for the point! I'll use #1 then.

-- 
  Alexander
From: Andrew Morton
Date: Wednesday, August 4, 2010 - 4:29 pm

On Thu,  5 Aug 2010 01:06:50 +0400

I suspect that if this warning ever triggers, it'll trigger at some
high frequency making a complete mess all over the floor.

WARN_ON_ONCE, perhaps?  Or just remove it?
--

From: Alexander Gordeev
Date: Thursday, August 5, 2010 - 5:29 am

В Wed, 4 Aug 2010 16:29:07 -0700

Well, getnstime_raw_and_real() is actually just a merge of
getnstimeofday() and getrawmonotonic(). The warning came from
getnstimeofday(). Usually this code should be called once a second but
the frequency can be higher. IMHO other functions like getnstimeofday()
and ktime_get_ts() would be a bigger problem anyway because they have
the same checks.

So I'm ok with either choice.
Hmm, will use WARN_ON_ONCE then if nobody objects.

-- 
  Alexander
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

This handler should be called from an IRQ handler. It uses per-device
workqueue internally.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/clients/pps-ktimer.c |    2 +-
 drivers/pps/clients/pps-ldisc.c  |    2 +-
 drivers/pps/kapi.c               |   95 ++++++++++++++++++++++++++++++++++++--
 drivers/pps/pps.c                |   14 +++++-
 include/linux/pps_kernel.h       |   16 ++++++-
 5 files changed, 119 insertions(+), 10 deletions(-)

diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
index 9d27239..61d0800 100644
--- a/drivers/pps/clients/pps-ktimer.c
+++ b/drivers/pps/clients/pps-ktimer.c
@@ -47,7 +47,7 @@ static void pps_ktimer_event(unsigned long ptr)
 
 	dev_info(pps->dev, "PPS event at %lu\n", jiffies);
 
-	pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
+	pps_event_irq(pps, &ts, PPS_CAPTUREASSERT, NULL);
 
 	mod_timer(&ktimer, jiffies + HZ);
 }
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index d7e1a27..3e64042 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -40,7 +40,7 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
 		ts = &__ts;
 
 	/* Now do the PPS event report */
-	pps_event(pps, ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
+	pps_event_irq(pps, ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
 			NULL);
 
 	dev_dbg(pps->dev, "PPS %s at %lu\n", status ? "assert" : "clear",
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 041c27e..d5f18ce 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -31,9 +31,19 @@
 #include <linux/slab.h>
 
 /*
+ * Global variables
+ */
+
+/* PPS event workqueue */
+struct workqueue_struct *pps_event_workqueue;
+
+/*
  * Local functions
  */
 
+static void assert_work_func(struct work_struct *work);
+static void clear_work_func(struct work_struct *work);
+
 static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime ...
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Add an optional feature of PPSAPI, kernel consumer support, which uses
the added hardpps() function.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 Documentation/ioctl/ioctl-number.txt |    2 +-
 drivers/pps/Kconfig                  |    1 +
 drivers/pps/kapi.c                   |   23 ++++++++++++
 drivers/pps/pps.c                    |   62 +++++++++++++++++++++++++++++++++-
 include/linux/pps.h                  |    7 ++++
 include/linux/pps_kernel.h           |    6 +++
 6 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e507f84 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -248,7 +248,7 @@ Code  Seq#(hex)	Include File		Comments
 'p'	40-7F	linux/nvram.h
 'p'	80-9F	linux/ppdev.h		user-space parport
 					<mailto:tim@cyberelk.net>
-'p'	A1-A4	linux/pps.h		LinuxPPS
+'p'	A1-A5	linux/pps.h		LinuxPPS
 					<mailto:giometti@linux.it>
 'q'	00-1F	linux/serio.h
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
index 33c9126..4823e47 100644
--- a/drivers/pps/Kconfig
+++ b/drivers/pps/Kconfig
@@ -7,6 +7,7 @@ menu "PPS support"
 config PPS
 	tristate "PPS support"
 	depends on EXPERIMENTAL
+	select NTP_PPS
 	---help---
 	  PPS (Pulse Per Second) is a special pulse provided by some GPS
 	  antennae. Userland can use it to get a high-precision time
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 0335b2c..02f4dd1 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/time.h>
+#include <linux/timex.h>
 #include <linux/spinlock.h>
 #include <linux/fs.h>
 #include <linux/pps_kernel.h>
@@ -37,6 +38,12 @@
 /* PPS event workqueue */
 struct workqueue_struct *pps_event_workqueue;
 
+/* state variables to bind kernel consumer */
+/* PPS API ...
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

This way less overhead is involved when running production kernel.
If you want to debug a pps client module please define DEBUG to enable
the checks.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/kapi.c |   33 ++++++++++-----------------------
 1 files changed, 10 insertions(+), 23 deletions(-)

diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 8c557c4..220ab08 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -80,25 +80,14 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
 	int err;
 
 	/* Sanity checks */
-	if ((info->mode & default_params) != default_params) {
-		pr_err("pps: %s: unsupported default parameters\n",
-					info->name);
-		err = -EINVAL;
-		goto pps_register_source_exit;
-	}
-	if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
-			info->echo == NULL) {
-		pr_err("pps: %s: echo function is not defined\n",
-					info->name);
-		err = -EINVAL;
-		goto pps_register_source_exit;
-	}
-	if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
-		pr_err("pps: %s: unspecified time format\n",
-					info->name);
-		err = -EINVAL;
-		goto pps_register_source_exit;
-	}
+
+	/* default_params should be supported */
+	BUG_ON((info->mode & default_params) != default_params);
+	/* echo function should be defined if we are asked to call it */
+	BUG_ON((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
+			info->echo == NULL);
+	/* time format should be specified */
+	BUG_ON((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0);
 
 	/* Allocate memory for the new PPS source struct */
 	pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL);
@@ -175,10 +164,8 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
 	int captured = 0;
 	struct pps_ktime ts_real;
 
-	if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
-		dev_err(pps->dev, "unknown event (%x)\n", event);
-		return;
-	}
+	/* check event type */
+	BUG_ON((event & ...
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Now all PPS spin locks are never used in interrupt context so we can
safely replace spin_lock_irq*/spin_unlock_irq* with plain
spin_lock/spin_unlock.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/kapi.c |    5 ++---
 drivers/pps/pps.c  |   24 ++++++++++++------------
 2 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index d5f18ce..8c557c4 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -172,7 +172,6 @@ EXPORT_SYMBOL(pps_unregister_source);
 void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
 		void *data)
 {
-	unsigned long flags;
 	int captured = 0;
 	struct pps_ktime ts_real;
 
@@ -186,7 +185,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
 
 	timespec_to_pps_ktime(&ts_real, ts->ts_real);
 
-	spin_lock_irqsave(&pps->lock, flags);
+	spin_lock(&pps->lock);
 
 	/* Must call the echo function? */
 	if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
@@ -233,7 +232,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
 		kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
 	}
 
-	spin_unlock_irqrestore(&pps->lock, flags);
+	spin_unlock(&pps->lock);
 }
 EXPORT_SYMBOL(pps_event);
 
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 81adb33..4f02718 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -73,12 +73,12 @@ static long pps_cdev_ioctl(struct file *file,
 	case PPS_GETPARAMS:
 		dev_dbg(pps->dev, "PPS_GETPARAMS\n");
 
-		spin_lock_irq(&pps->lock);
+		spin_lock(&pps->lock);
 
 		/* Get the current parameters */
 		params = pps->params;
 
-		spin_unlock_irq(&pps->lock);
+		spin_unlock(&pps->lock);
 
 		err = copy_to_user(uarg, &params, sizeof(struct pps_kparams));
 		if (err)
@@ -109,7 +109,7 @@ static long pps_cdev_ioctl(struct file *file,
 			return -EINVAL;
 		}
 
-		spin_lock_irq(&pps->lock);
+		spin_lock(&pps->lock);
 
 		/* Save the new ...
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Add parallel port PPS client. It uses a standard method for capturing
timestamps for assert edge transitions: getting a timestamp soon after
an interrupt has happened. This is not a very precise source of time
information due to interrupt handling delays. However, timestamps for
clear edge transitions are much more precise because the interrupt
handler continuously polls hardware port until the transition is done.
Hardware port operations require only about 1us so the maximum error
should not exceed this value. This was my primary goal when developing
this client.
Clear edge capture could be disabled using clear_wait parameter.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/clients/Kconfig       |    7 +
 drivers/pps/clients/Makefile      |    1 +
 drivers/pps/clients/pps_parport.c |  244 +++++++++++++++++++++++++++++++++++++
 3 files changed, 252 insertions(+), 0 deletions(-)
 create mode 100644 drivers/pps/clients/pps_parport.c

diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig
index 4e801bd..8520a7f 100644
--- a/drivers/pps/clients/Kconfig
+++ b/drivers/pps/clients/Kconfig
@@ -22,4 +22,11 @@ config PPS_CLIENT_LDISC
 	  If you say yes here you get support for a PPS source connected
 	  with the CD (Carrier Detect) pin of your serial port.
 
+config PPS_CLIENT_PARPORT
+	tristate "Parallel port PPS client"
+	depends on PPS && PARPORT
+	help
+	  If you say yes here you get support for a PPS source connected
+	  with the interrupt pin of your parallel port.
+
 endif
diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile
index 812c9b1..42517da 100644
--- a/drivers/pps/clients/Makefile
+++ b/drivers/pps/clients/Makefile
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_PPS_CLIENT_KTIMER)	+= pps-ktimer.o
 obj-$(CONFIG_PPS_CLIENT_LDISC)	+= pps-ldisc.o
+obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
 
 ifeq ($(CONFIG_PPS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/pps/clients/pps_parport.c ...
From: Andrew Morton
Date: Wednesday, August 4, 2010 - 4:34 pm

On Thu,  5 Aug 2010 01:06:52 +0400

This could (and hence should) be implemented in a regular old C

eww.  parport_driver.attach() returns void so there's no way to
--

From: Alexander Gordeev
Date: Thursday, August 5, 2010 - 5:48 am

В Wed, 4 Aug 2010 16:34:30 -0700


IMHO, the whole parport thing currently sucks quite a bit.

-- 
  Alexander
From: Alexander Gordeev
Date: Wednesday, August 4, 2010 - 2:06 pm

Add PPS signal generator which utilizes STROBE pin of a parallel port to
send PPS signals. It uses parport abstraction layer and hrtimers to
precisely control the signal.

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
 drivers/pps/Kconfig                      |    2 +
 drivers/pps/Makefile                     |    2 +-
 drivers/pps/generators/Kconfig           |   17 ++
 drivers/pps/generators/Makefile          |    9 +
 drivers/pps/generators/pps_gen_parport.c |  274 ++++++++++++++++++++++++++++++
 5 files changed, 303 insertions(+), 1 deletions(-)
 create mode 100644 drivers/pps/generators/Kconfig
 create mode 100644 drivers/pps/generators/Makefile
 create mode 100644 drivers/pps/generators/pps_gen_parport.c

diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
index 4823e47..79bda60 100644
--- a/drivers/pps/Kconfig
+++ b/drivers/pps/Kconfig
@@ -40,4 +40,6 @@ config NTP_PPS
 
 source drivers/pps/clients/Kconfig
 
+source drivers/pps/generators/Kconfig
+
 endmenu
diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile
index 98960dd..1906eb7 100644
--- a/drivers/pps/Makefile
+++ b/drivers/pps/Makefile
@@ -4,6 +4,6 @@
 
 pps_core-y			:= pps.o kapi.o sysfs.o
 obj-$(CONFIG_PPS)		:= pps_core.o
-obj-y				+= clients/
+obj-y				+= clients/ generators/
 
 ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/pps/generators/Kconfig b/drivers/pps/generators/Kconfig
new file mode 100644
index 0000000..5fbd614
--- /dev/null
+++ b/drivers/pps/generators/Kconfig
@@ -0,0 +1,17 @@
+#
+# PPS generators configuration
+#
+
+if PPS
+
+comment "PPS generators support"
+
+config PPS_GENERATOR_PARPORT
+	tristate "Parallel port PPS signal generator"
+	depends on PARPORT != n && GENERIC_TIME
+	help
+	  If you say yes here you get support for a PPS signal generator which
+	  utilizes STROBE pin of a parallel port to send PPS signals. It uses
+	  parport abstraction layer and hrtimers to precisely control the signal.
+
+endif
diff --git ...
From: Andrew Morton
Date: Wednesday, August 4, 2010 - 4:38 pm

On Thu,  5 Aug 2010 01:06:53 +0400

This code doesn't look easy to configure and use.  For example, if some
random person tries to get it going, how does he even know that this
module parameter exists, let alone how to use it?

Please review Documentation/pps/pps.txt and check that it accurately
and completely describes how to use the pps code after your changes,
thanks.

--

Previous thread: [PATCHv3 05/16] pps: access pps device by direct pointer by Alexander Gordeev on Wednesday, August 4, 2010 - 2:06 pm. (6 messages)

Next thread: [PATCH 2/3] perf: expose event__process function by Arnaldo Carvalho de Melo on Wednesday, August 4, 2010 - 2:26 pm. (1 message)