[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