[LinuxPPS] [alpha PATCH] Low level IRQ support.

Rodolfo Giometti giometti at enneenne.com
Sun May 4 11:02:43 CEST 2008


On Sat, May 03, 2008 at 09:07:09AM +0200, Udo van den Heuvel wrote:
> Rodolfo Giometti wrote:
> >> If you have suggestions to (better) compare old and new behaviour,
> >> please let me know.
> > 
> > Yes, please, try to set CONFIG_PPS_IRQ_EVENTS=n and compare the
> > improvements.
> 
> I do think we might need graphs like the one at
> http://aiken.dnsalias.org/irq-pps-cpu.png to compare the performance and
> see possible improvements.

:)

> Can we make the irq-events.patch x86_64-comaptible? (i.e. x86-generic)

Try the attached patch (warning: still untested! :)

Ciao,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail:    giometti at enneenne.com
Linux Device Driver                             giometti at linux.it
Embedded Systems                     phone:	+39 349 2432127
UNIX programming                     skype:     rodolfo.giometti
-------------- next part --------------
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index d3fde94..a3b8457 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -15,6 +15,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/delay.h>
+#include <linux/pps.h>
 
 #include <asm/apic.h>
 #include <asm/uaccess.h>
@@ -25,6 +26,11 @@ EXPORT_PER_CPU_SYMBOL(irq_stat);
 DEFINE_PER_CPU(struct pt_regs *, irq_regs);
 EXPORT_PER_CPU_SYMBOL(irq_regs);
 
+#ifdef CONFIG_PPS_IRQ_EVENTS
+struct pps_ktime pps_irq_ts[NR_IRQS];
+EXPORT_SYMBOL(pps_irq_ts);
+#endif
+
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
@@ -76,6 +82,12 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
 	union irq_ctx *curctx, *irqctx;
 	u32 *isp;
 #endif
+#ifdef CONFIG_PPS_IRQ_EVENTS
+	struct timespec __ts;
+
+	/* Get IRQ timestamps as soon as possible for the PPS layer */
+	getnstimeofday(&__ts);
+#endif
 
 	if (unlikely((unsigned)irq >= NR_IRQS)) {
 		printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
@@ -83,6 +95,12 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
 		BUG();
 	}
 
+#ifdef CONFIG_PPS_IRQ_EVENTS
+	/* Then, after sanity check, store the IRQ timestamp */
+	pps_irq_ts[irq].sec = __ts.tv_sec;
+	pps_irq_ts[irq].nsec = __ts.tv_nsec;
+#endif
+
 	old_regs = set_irq_regs(regs);
 	irq_enter();
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
index 6b5c730..afe5559 100644
--- a/arch/x86/kernel/irq_64.c
+++ b/arch/x86/kernel/irq_64.c
@@ -17,9 +17,15 @@
 #include <asm/io_apic.h>
 #include <asm/idle.h>
 #include <asm/smp.h>
+#include <linux/pps.h>
 
 atomic_t irq_err_count;
 
+#ifdef CONFIG_PPS_IRQ_EVENTS
+struct pps_ktime pps_irq_ts[NR_IRQS];
+EXPORT_SYMBOL(pps_irq_ts);
+#endif
+
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 /*
  * Probabilistic stack overflow check:
@@ -140,6 +146,12 @@ skip:
 asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
+#ifdef CONFIG_PPS_IRQ_EVENTS
+	struct timespec __ts;
+
+	/* Get IRQ timestamps as soon as possible for the PPS layer */
+	getnstimeofday(&__ts);
+#endif
 
 	/* high bit used in ret_from_ code  */
 	unsigned vector = ~regs->orig_rax;
@@ -153,9 +165,15 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
 	stack_overflow_check(regs);
 #endif
 
-	if (likely(irq < NR_IRQS))
+	if (likely(irq < NR_IRQS)) {
+#ifdef CONFIG_PPS_IRQ_EVENTS
+		/* Then, after sanity check, store the IRQ timestamp */
+		pps_irq_ts[irq].sec = __ts.tv_sec;
+		pps_irq_ts[irq].nsec = __ts.tv_nsec;
+#endif
+
 		generic_handle_irq(irq);
-	else {
+	} else {
 		if (!disable_apic)
 			ack_APIC_irq();
 
diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
index 5d91657..cf04837 100644
--- a/drivers/pps/Kconfig
+++ b/drivers/pps/Kconfig
@@ -22,6 +22,18 @@ config PPS
 	  To compile this driver as a module, choose M here: the module
 	  will be called pps_core.ko.
 
+config PPS_IRQ_EVENTS
+	bool "Use low level IRQ timestamps"
+	depends on PPS && (X86_32 || X86_64)
+	default yes
+	help
+	  Say Y here if you wish using low level IRQ timestamps to register
+	  PPS events.
+
+	  This should improve PPS resolution but it delays echo functions
+	  call. Note also that this function is not implemented on all
+	  platforms and PPS clients!
+
 config PPS_DEBUG
 	bool "PPS debugging messages"
 	depends on PPS 
diff --git a/drivers/pps/clients/ktimer.c b/drivers/pps/clients/ktimer.c
index 5845188..a8b71b1 100644
--- a/drivers/pps/clients/ktimer.c
+++ b/drivers/pps/clients/ktimer.c
@@ -41,9 +41,19 @@ static struct timer_list ktimer;
 
 static void pps_ktimer_event(unsigned long ptr)
 {
+	struct timespec __ts;
+	struct pps_ktime ts;
+
+	/* First of all we get the time stamp... */
+	getnstimeofday(&__ts);
+
+	/* ... and translate it to PPS time data struct */
+	ts.sec = __ts.tv_sec;
+	ts.nsec = __ts.tv_nsec;
+
 	pr_info("PPS event at %lu\n", jiffies);
 
-	pps_event(source, PPS_CAPTUREASSERT, NULL);
+	pps_event(source, &ts, PPS_CAPTUREASSERT, NULL);
 
 	mod_timer(&ktimer, jiffies + HZ);
 }
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 6c72e2e..1a87856 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/spinlock.h>
@@ -248,6 +249,7 @@ EXPORT_SYMBOL(pps_unregister_source);
 /* pps_event - register a PPS event into the system
  *
  *	source: the PPS source ID
+ *	ts: the event timestamp
  *	event: the event type
  *	data: userdef pointer
  *
@@ -259,20 +261,11 @@ EXPORT_SYMBOL(pps_unregister_source);
  *	pps->info.echo(source, event, data);
  */
 
-void pps_event(int source, int event, void *data)
+void pps_event(int source, struct pps_ktime *ts, int event, void *data)
 {
 	struct pps_device *pps;
-	struct timespec __ts;
-	struct pps_ktime ts;
 	unsigned long flags;
 
-	/* First of all we get the time stamp... */
-	getnstimeofday(&__ts);
-
-	/* ... and translate it to PPS time data struct */
-	ts.sec = __ts.tv_sec;
-	ts.nsec = __ts.tv_nsec;
-
 	if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
 		printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
 			event, source);
@@ -284,7 +277,7 @@ void pps_event(int source, int event, void *data)
 		return;
 
 	pr_debug("PPS event on source %d at %llu.%06u\n",
-			pps->id, (unsigned long long) ts.sec, ts.nsec);
+			pps->id, (unsigned long long) ts->sec, ts->nsec);
 
 	spin_lock_irqsave(&pps->lock, flags);
 
@@ -297,10 +290,10 @@ void pps_event(int source, int event, void *data)
 	if (event & PPS_CAPTUREASSERT) {
 		/* We have to add an offset? */
 		if (pps->params.mode & PPS_OFFSETASSERT)
-			pps_add_offset(&ts, &pps->params.assert_off_tu);
+			pps_add_offset(ts, &pps->params.assert_off_tu);
 
 		/* Save the time stamp */
-		pps->assert_tu = ts;
+		pps->assert_tu = *ts;
 		pps->assert_sequence++;
 		pr_debug("capture assert seq #%u for source %d\n",
 			pps->assert_sequence, source);
@@ -308,10 +301,10 @@ void pps_event(int source, int event, void *data)
 	if (event & PPS_CAPTURECLEAR) {
 		/* We have to add an offset? */
 		if (pps->params.mode & PPS_OFFSETCLEAR)
-			pps_add_offset(&ts, &pps->params.clear_off_tu);
+			pps_add_offset(ts, &pps->params.clear_off_tu);
 
 		/* Save the time stamp */
-		pps->clear_tu = ts;
+		pps->clear_tu = *ts;
 		pps->clear_sequence++;
 		pr_debug("capture clear seq #%u for source %d\n",
 			pps->clear_sequence, source);
diff --git a/include/linux/parport.h b/include/linux/parport.h
index 501a9dc..b2c6be9 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -523,7 +523,17 @@ extern int parport_daisy_select (struct parport *port, int daisy, int mode);
 static inline void parport_generic_irq(struct parport *port)
 {
 #ifdef CONFIG_PPS_CLIENT_LP
-	pps_event(port->pps_source, PPS_CAPTUREASSERT, port);
+	struct timespec __ts;
+	struct pps_ktime ts;
+
+	/* First of all we get the time stamp... */
+	getnstimeofday(&__ts);
+
+	/* ... and translate it to PPS time data struct */
+	ts.sec = __ts.tv_sec;
+	ts.nsec = __ts.tv_nsec;
+
+	pps_event(port->pps_source, &ts, PPS_CAPTUREASSERT, port);
 	dev_dbg(port->dev, "PPS assert at %lu on source #%d\n",
 		jiffies, port->pps_source);
 #endif
diff --git a/include/linux/pps.h b/include/linux/pps.h
index 83a23d2..da0fc9a 100644
--- a/include/linux/pps.h
+++ b/include/linux/pps.h
@@ -181,6 +181,7 @@ struct pps_device {
 
 extern spinlock_t pps_idr_lock;
 extern struct idr pps_idr;
+extern struct pps_ktime pps_irq_ts[];
 
 extern struct device_attribute pps_attrs[];
 
@@ -195,7 +196,7 @@ extern int pps_register_source(struct pps_source_info *info,
 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, int event, void *data);
+extern void pps_event(int source, struct pps_ktime *ts, int event, void *data);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index c8e4d92..a80d1ea 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -490,16 +490,27 @@ uart_handle_dcd_change(struct uart_port *port, unsigned int status)
 	struct uart_info *info = port->info;
 
 #ifdef CONFIG_PPS_CLIENT_UART
+	struct timespec __ts;
+	struct pps_ktime ts;
+
+	/* First of all we get the time stamp... */
+	getnstimeofday(&__ts);
+
+	/* ... and translate it to PPS time data struct */
+	ts.sec = __ts.tv_sec;
+	ts.nsec = __ts.tv_nsec;
+
 	if (port->flags & UPF_HARDPPS_CD) {
-		if (status) {
-			pps_event(port->pps_source, PPS_CAPTUREASSERT, port);
-			dev_dbg(port->dev, "PPS assert at %lu on source #%d\n",
-				jiffies, port->pps_source);
-		} else {
-			pps_event(port->pps_source, PPS_CAPTURECLEAR, port);
-			dev_dbg(port->dev, "PPS clear at %lu on source #%d\n",
-				jiffies, port->pps_source);
-		}
+		pps_event(port->pps_source,
+#ifdef CONFIG_PPS_IRQ_EVENTS
+				&pps_irq_ts[port->irq],
+#else
+				&ts,
+#endif
+				status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
+				port);
+		dev_dbg(port->dev, "PPS %s at %lu on source #%d\n",
+			status ? "assert" : "clear", jiffies, port->pps_source);
 	}
 #endif
 


More information about the LinuxPPS mailing list