linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] atmel_tc library
@ 2008-03-04 13:07 Haavard Skinnemoen
  2008-03-04 13:07 ` [PATCH] atmel_tc clocksource/clockevent code Haavard Skinnemoen
  0 siblings, 1 reply; 10+ messages in thread
From: Haavard Skinnemoen @ 2008-03-04 13:07 UTC (permalink / raw)
  To: akpm
  Cc: LKML, David Brownell, David Brownell, Haavard Skinnemoen,
	Nicolas Ferre, Andrew Victor

From: David Brownell <david-b@pacbell.net>

Create <linux/atmel_tc.h> based on <asm-arm/arch-at91/at91-tc.h> and the
at91sam9263 and at32ap7000 datasheets.  Most AT91 and AT32 SOCs have one
or two of these TC blocks, which include three 16-bit timers that can be
interconnected in various ways.

These TC blocks can be used for external interfacing (such as PWM and
measurement), or used as somewhat quirky sixteen-bit timers.

Changes relative to the original version:
  * Drop unneeded inclusion of <linux/mutex.h>
  * Support an arbitrary number of TC blocks
  * Return a struct with information about a TC block from
    atmel_tc_alloc() instead of using a combination of return values
    and "out" parameters.
  * ioremap() the I/O registers on allocation
  * Look up clocks and irqs for all channels
  * Add "name" parameter to atmel_tc_alloc() and use this when
    requesting the iomem resource.
  * Check if the platform provided the necessary resources at probe()
    time instead of when the TCB is allocated.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
Cc: Andrew Victor <linux@maxim.org.za>
---
This patch is meant to replace atmel_tc-library.patch

 drivers/misc/Kconfig       |    8 ++
 drivers/misc/Makefile      |    1 +
 drivers/misc/atmel_tclib.c |  161 ++++++++++++++++++++++++++++
 include/linux/atmel_tc.h   |  252 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 422 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/atmel_tclib.c
 create mode 100644 include/linux/atmel_tc.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 982e27b..b3ba681 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -22,6 +22,14 @@ config ATMEL_PWM
 	  purposes including software controlled power-efficent backlights
 	  on LCD displays, motor control, and waveform generation.
 
+config ATMEL_TCLIB
+	bool "Atmel AT32/AT91 Timer/Counter Library"
+	depends on (AVR32 || ARCH_AT91)
+	help
+	  Select this if you want a library to allocate the Timer/Counter
+	  blocks found on many Atmel processors.  This facilitates using
+	  these blocks by different drivers despite processor differences.
+
 config IBM_ASM
 	tristate "Device driver for IBM RSA service processor"
 	depends on X86 && PCI && INPUT && EXPERIMENTAL
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3b12f5d..c975028 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_ACER_WMI)     += acer-wmi.o
 obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
 obj-$(CONFIG_ATMEL_PWM)		+= atmel_pwm.o
 obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc.o
+obj-$(CONFIG_ATMEL_TCLIB)	+= atmel_tclib.o
 obj-$(CONFIG_TC1100_WMI)	+= tc1100-wmi.o
 obj-$(CONFIG_LKDTM)		+= lkdtm.o
 obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c
new file mode 100644
index 0000000..05dc8a3
--- /dev/null
+++ b/drivers/misc/atmel_tclib.c
@@ -0,0 +1,161 @@
+#include <linux/atmel_tc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+/* Number of bytes to reserve for the iomem resource */
+#define ATMEL_TC_IOMEM_SIZE	256
+
+
+/*
+ * This is a thin library to solve the problem of how to portably allocate
+ * one of the TC blocks.  For simplicity, it doesn't currently expect to
+ * share individual timers between different drivers.
+ */
+
+#if defined(CONFIG_AVR32)
+/* AVR32 has these divide PBB */
+const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, };
+EXPORT_SYMBOL(atmel_tc_divisors);
+
+#elif defined(CONFIG_ARCH_AT91)
+/* AT91 has these divide MCK */
+const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, };
+EXPORT_SYMBOL(atmel_tc_divisors);
+
+#endif
+
+static DEFINE_SPINLOCK(tc_list_lock);
+static LIST_HEAD(tc_list);
+
+/**
+ * atmel_tc_alloc - allocate a specified TC block
+ * @block: which block to allocate
+ * @name: name to be associated with the iomem resource
+ *
+ * Caller allocates a block.  If it is available, a pointer to a
+ * pre-initialized struct atmel_tc is returned. The caller can access
+ * the registers directly through the "regs" field.
+ */
+struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
+{
+	struct atmel_tc		*tc;
+	struct platform_device	*pdev = NULL;
+	struct resource		*r;
+
+	spin_lock(&tc_list_lock);
+	list_for_each_entry(tc, &tc_list, node) {
+		if (tc->pdev->id == block) {
+			pdev = tc->pdev;
+			break;
+		}
+	}
+
+	if (!pdev || tc->iomem)
+		goto fail;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
+	if (!r)
+		goto fail;
+
+	tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
+	if (!tc->regs)
+		goto fail_ioremap;
+
+	tc->iomem = r;
+
+out:
+	spin_unlock(&tc_list_lock);
+	return tc;
+
+fail_ioremap:
+	release_resource(r);
+fail:
+	tc = NULL;
+	goto out;
+}
+EXPORT_SYMBOL_GPL(atmel_tc_alloc);
+
+/**
+ * atmel_tc_free - release a specified TC block
+ * @tc: Timer/counter block that was returned by atmel_tc_alloc()
+ *
+ * This reverses the effect of atmel_tc_alloc(), unmapping the I/O
+ * registers, invalidating the resource returned by that routine and
+ * making the TC available to other drivers.
+ */
+void atmel_tc_free(struct atmel_tc *tc)
+{
+	spin_lock(&tc_list_lock);
+	if (tc->regs) {
+		iounmap(tc->regs);
+		release_resource(tc->iomem);
+		tc->regs = NULL;
+		tc->iomem = NULL;
+	}
+	spin_unlock(&tc_list_lock);
+}
+EXPORT_SYMBOL_GPL(atmel_tc_free);
+
+static int __init tc_probe(struct platform_device *pdev)
+{
+	struct atmel_tc *tc;
+	struct clk	*clk;
+	int		irq;
+
+	if (!platform_get_resource(pdev, IORESOURCE_MEM, 0))
+		return -EINVAL;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -EINVAL;
+
+	tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL);
+	if (!tc)
+		return -ENOMEM;
+
+	tc->pdev = pdev;
+
+	clk = clk_get(&pdev->dev, "t0_clk");
+	if (IS_ERR(clk)) {
+		kfree(tc);
+		return -EINVAL;
+	}
+
+	tc->clk[0] = clk;
+	tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
+	if (IS_ERR(tc->clk[1]))
+		tc->clk[1] = clk;
+	tc->clk[2] = clk_get(&pdev->dev, "t2_clk");
+	if (IS_ERR(tc->clk[2]))
+		tc->clk[2] = clk;
+
+	tc->irq[0] = irq;
+	tc->irq[1] = platform_get_irq(pdev, 1);
+	if (tc->irq[1] < 0)
+		tc->irq[1] = irq;
+	tc->irq[2] = platform_get_irq(pdev, 2);
+	if (tc->irq[2] < 0)
+		tc->irq[2] = irq;
+
+	spin_lock(&tc_list_lock);
+	list_add_tail(&tc->node, &tc_list);
+	spin_unlock(&tc_list_lock);
+
+	return 0;
+}
+
+static struct platform_driver tc_driver = {
+	.driver.name	= "atmel_tcb",
+};
+
+static int __init tc_init(void)
+{
+	return platform_driver_probe(&tc_driver, tc_probe);
+}
+arch_initcall(tc_init);
diff --git a/include/linux/atmel_tc.h b/include/linux/atmel_tc.h
new file mode 100644
index 0000000..53ba65e
--- /dev/null
+++ b/include/linux/atmel_tc.h
@@ -0,0 +1,252 @@
+/*
+ * Timer/Counter Unit (TC) registers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ATMEL_TC_H
+#define ATMEL_TC_H
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+
+/*
+ * Many 32-bit Atmel SOCs include one or more TC blocks, each of which holds
+ * three general-purpose 16-bit timers.  These timers share one register bank.
+ * Depending on the SOC, each timer may have its own clock and IRQ, or those
+ * may be shared by the whole TC block.
+ *
+ * These TC blocks may have up to nine external pins:  TCLK0..2 signals for
+ * clocks or clock gates, and per-timer TIOA and TIOB signals used for PWM
+ * or triggering.  Those pins need to be set up for use with the TC block,
+ * else they will be used as GPIOs or for a different controller.
+ *
+ * Although we expect each TC block to have a platform_device node, those
+ * nodes are not what drivers bind to.  Instead, they ask for a specific
+ * TC block, by number ... which is a common approach on systems with many
+ * timers.  Then they use clk_get() and platform_get_irq() to get clock and
+ * IRQ resources.
+ */
+
+struct clk;
+
+/**
+ * struct atmel_tc - information about a Timer/Counter Block
+ * @pdev: physical device
+ * @iomem: resource associated with the I/O register
+ * @regs: mapping through which the I/O registers can be accessed
+ * @irq: irq for each of the three channels
+ * @clk: internal clock source for each of the three channels
+ * @node: list node, for tclib internal use
+ *
+ * On some platforms, each TC channel has its own clocks and IRQs,
+ * while on others, all TC channels share the same clock and IRQ.
+ * Drivers should clk_enable() all the clocks they need even though
+ * all the entries in @clk may point to the same physical clock.
+ * Likewise, drivers should request irqs independently for each
+ * channel, but they must use IRQF_SHARED in case some of the entries
+ * in @irq are actually the same IRQ.
+ */
+struct atmel_tc {
+	struct platform_device	*pdev;
+	struct resource		*iomem;
+	void __iomem		*regs;
+	int			irq[3];
+	struct clk		*clk[3];
+	struct list_head	node;
+};
+
+extern struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name);
+extern void atmel_tc_free(struct atmel_tc *tc);
+
+/* platform-specific ATMEL_TC_TIMER_CLOCKx divisors (0 means 32KiHz) */
+extern const u8 atmel_tc_divisors[5];
+
+
+/*
+ * Two registers have block-wide controls.  These are: configuring the three
+ * "external" clocks (or event sources) used by the timer channels; and
+ * synchronizing the timers by resetting them all at once.
+ *
+ * "External" can mean "external to chip" using the TCLK0, TCLK1, or TCLK2
+ * signals.  Or, it can mean "external to timer", using the TIOA output from
+ * one of the other two timers that's being run in waveform mode.
+ */
+
+#define ATMEL_TC_BCR	0xc0		/* TC Block Control Register */
+#define     ATMEL_TC_SYNC	(1 << 0)	/* synchronize timers */
+
+#define ATMEL_TC_BMR	0xc4		/* TC Block Mode Register */
+#define     ATMEL_TC_TC0XC0S	(3 << 0)	/* external clock 0 source */
+#define        ATMEL_TC_TC0XC0S_TCLK0	(0 << 0)
+#define        ATMEL_TC_TC0XC0S_NONE	(1 << 0)
+#define        ATMEL_TC_TC0XC0S_TIOA1	(2 << 0)
+#define        ATMEL_TC_TC0XC0S_TIOA2	(3 << 0)
+#define     ATMEL_TC_TC1XC1S	(3 << 2)	/* external clock 1 source */
+#define        ATMEL_TC_TC1XC1S_TCLK1	(0 << 2)
+#define        ATMEL_TC_TC1XC1S_NONE	(1 << 2)
+#define        ATMEL_TC_TC1XC1S_TIOA0	(2 << 2)
+#define        ATMEL_TC_TC1XC1S_TIOA2	(3 << 2)
+#define     ATMEL_TC_TC2XC2S	(3 << 4)	/* external clock 2 source */
+#define        ATMEL_TC_TC2XC2S_TCLK2	(0 << 4)
+#define        ATMEL_TC_TC2XC2S_NONE	(1 << 4)
+#define        ATMEL_TC_TC2XC2S_TIOA0	(2 << 4)
+#define        ATMEL_TC_TC2XC2S_TIOA1	(3 << 4)
+
+
+/*
+ * Each TC block has three "channels", each with one counter and controls.
+ *
+ * Note that the semantics of ATMEL_TC_TIMER_CLOCKx (input clock selection
+ * when it's not "external") is silicon-specific.  AT91 platforms use one
+ * set of definitions; AVR32 platforms use a different set.  Don't hard-wire
+ * such knowledge into your code, use the global "atmel_tc_divisors" ...
+ * where index N is the divisor for clock N+1, else zero to indicate it uses
+ * the 32 KiHz clock.
+ *
+ * The timers can be chained in various ways, and operated in "waveform"
+ * generation mode (including PWM) or "capture" mode (to time events).  In
+ * both modes, behavior can be configured in many ways.
+ *
+ * Each timer has two I/O pins, TIOA and TIOB.  Waveform mode uses TIOA as a
+ * PWM output, and TIOB as either another PWM or as a trigger.  Capture mode
+ * uses them only as inputs.
+ */
+#define ATMEL_TC_CHAN(idx)	((idx)*0x40)
+#define ATMEL_TC_REG(idx, reg)	(ATMEL_TC_CHAN(idx) + ATMEL_TC_ ## reg)
+
+#define ATMEL_TC_CCR	0x00		/* Channel Control Register */
+#define     ATMEL_TC_CLKEN	(1 << 0)	/* clock enable */
+#define     ATMEL_TC_CLKDIS	(1 << 1)	/* clock disable */
+#define     ATMEL_TC_SWTRG	(1 << 2)	/* software trigger */
+
+#define ATMEL_TC_CMR	0x04		/* Channel Mode Register */
+
+/* Both modes share some CMR bits */
+#define     ATMEL_TC_TCCLKS	(7 << 0)	/* clock source */
+#define        ATMEL_TC_TIMER_CLOCK1	(0 << 0)
+#define        ATMEL_TC_TIMER_CLOCK2	(1 << 0)
+#define        ATMEL_TC_TIMER_CLOCK3	(2 << 0)
+#define        ATMEL_TC_TIMER_CLOCK4	(3 << 0)
+#define        ATMEL_TC_TIMER_CLOCK5	(4 << 0)
+#define        ATMEL_TC_XC0		(5 << 0)
+#define        ATMEL_TC_XC1		(6 << 0)
+#define        ATMEL_TC_XC2		(7 << 0)
+#define     ATMEL_TC_CLKI	(1 << 3)	/* clock invert */
+#define     ATMEL_TC_BURST	(3 << 4)	/* clock gating */
+#define        ATMEL_TC_GATE_NONE	(0 << 4)
+#define        ATMEL_TC_GATE_XC0	(1 << 4)
+#define        ATMEL_TC_GATE_XC1	(2 << 4)
+#define        ATMEL_TC_GATE_XC2	(3 << 4)
+#define     ATMEL_TC_WAVE	(1 << 15)	/* true = Waveform mode */
+
+/* CAPTURE mode CMR bits */
+#define     ATMEL_TC_LDBSTOP	(1 << 6)	/* counter stops on RB load */
+#define     ATMEL_TC_LDBDIS	(1 << 7)	/* counter disable on RB load */
+#define     ATMEL_TC_ETRGEDG	(3 << 8)	/* external trigger edge */
+#define        ATMEL_TC_ETRGEDG_NONE	(0 << 8)
+#define        ATMEL_TC_ETRGEDG_RISING	(1 << 8)
+#define        ATMEL_TC_ETRGEDG_FALLING	(2 << 8)
+#define        ATMEL_TC_ETRGEDG_BOTH	(3 << 8)
+#define     ATMEL_TC_ABETRG	(1 << 10)	/* external trigger is TIOA? */
+#define     ATMEL_TC_CPCTRG	(1 << 14)	/* RC compare trigger enable */
+#define     ATMEL_TC_LDRA	(3 << 16)	/* RA loading edge (of TIOA) */
+#define        ATMEL_TC_LDRA_NONE	(0 << 16)
+#define        ATMEL_TC_LDRA_RISING	(1 << 16)
+#define        ATMEL_TC_LDRA_FALLING	(2 << 16)
+#define        ATMEL_TC_LDRA_BOTH	(3 << 16)
+#define     ATMEL_TC_LDRB	(3 << 18)	/* RB loading edge (of TIOA) */
+#define        ATMEL_TC_LDRB_NONE	(0 << 18)
+#define        ATMEL_TC_LDRB_RISING	(1 << 18)
+#define        ATMEL_TC_LDRB_FALLING	(2 << 18)
+#define        ATMEL_TC_LDRB_BOTH	(3 << 18)
+
+/* WAVEFORM mode CMR bits */
+#define     ATMEL_TC_CPCSTOP	(1 <<  6)	/* RC compare stops counter */
+#define     ATMEL_TC_CPCDIS	(1 <<  7)	/* RC compare disables counter */
+#define     ATMEL_TC_EEVTEDG	(3 <<  8)	/* external event edge */
+#define        ATMEL_TC_EEVTEDG_NONE	(0 << 8)
+#define        ATMEL_TC_EEVTEDG_RISING	(1 << 8)
+#define        ATMEL_TC_EEVTEDG_FALLING	(2 << 8)
+#define        ATMEL_TC_EEVTEDG_BOTH	(3 << 8)
+#define     ATMEL_TC_EEVT	(3 << 10)	/* external event source */
+#define        ATMEL_TC_EEVT_TIOB	(0 << 10)
+#define        ATMEL_TC_EEVT_XC0	(1 << 10)
+#define        ATMEL_TC_EEVT_XC1	(2 << 10)
+#define        ATMEL_TC_EEVT_XC2	(3 << 10)
+#define     ATMEL_TC_ENETRG	(1 << 12)	/* external event is trigger */
+#define     ATMEL_TC_WAVESEL	(3 << 13)	/* waveform type */
+#define        ATMEL_TC_WAVESEL_UP	(0 << 13)
+#define        ATMEL_TC_WAVESEL_UPDOWN	(1 << 13)
+#define        ATMEL_TC_WAVESEL_UP_AUTO	(2 << 13)
+#define        ATMEL_TC_WAVESEL_UPDOWN_AUTO (3 << 13)
+#define     ATMEL_TC_ACPA	(3 << 16)	/* RA compare changes TIOA */
+#define        ATMEL_TC_ACPA_NONE	(0 << 16)
+#define        ATMEL_TC_ACPA_SET	(1 << 16)
+#define        ATMEL_TC_ACPA_CLEAR	(2 << 16)
+#define        ATMEL_TC_ACPA_TOGGLE	(3 << 16)
+#define     ATMEL_TC_ACPC	(3 << 18)	/* RC compare changes TIOA */
+#define        ATMEL_TC_ACPC_NONE	(0 << 18)
+#define        ATMEL_TC_ACPC_SET	(1 << 18)
+#define        ATMEL_TC_ACPC_CLEAR	(2 << 18)
+#define        ATMEL_TC_ACPC_TOGGLE	(3 << 18)
+#define     ATMEL_TC_AEEVT	(3 << 20)	/* external event changes TIOA */
+#define        ATMEL_TC_AEEVT_NONE	(0 << 20)
+#define        ATMEL_TC_AEEVT_SET	(1 << 20)
+#define        ATMEL_TC_AEEVT_CLEAR	(2 << 20)
+#define        ATMEL_TC_AEEVT_TOGGLE	(3 << 20)
+#define     ATMEL_TC_ASWTRG	(3 << 22)	/* software trigger changes TIOA */
+#define        ATMEL_TC_ASWTRG_NONE	(0 << 22)
+#define        ATMEL_TC_ASWTRG_SET	(1 << 22)
+#define        ATMEL_TC_ASWTRG_CLEAR	(2 << 22)
+#define        ATMEL_TC_ASWTRG_TOGGLE	(3 << 22)
+#define     ATMEL_TC_BCPB	(3 << 24)	/* RB compare changes TIOB */
+#define        ATMEL_TC_BCPB_NONE	(0 << 24)
+#define        ATMEL_TC_BCPB_SET	(1 << 24)
+#define        ATMEL_TC_BCPB_CLEAR	(2 << 24)
+#define        ATMEL_TC_BCPB_TOGGLE	(3 << 24)
+#define     ATMEL_TC_BCPC	(3 << 26)	/* RC compare changes TIOB */
+#define        ATMEL_TC_BCPC_NONE	(0 << 26)
+#define        ATMEL_TC_BCPC_SET	(1 << 26)
+#define        ATMEL_TC_BCPC_CLEAR	(2 << 26)
+#define        ATMEL_TC_BCPC_TOGGLE	(3 << 26)
+#define     ATMEL_TC_BEEVT	(3 << 28)	/* external event changes TIOB */
+#define        ATMEL_TC_BEEVT_NONE	(0 << 28)
+#define        ATMEL_TC_BEEVT_SET	(1 << 28)
+#define        ATMEL_TC_BEEVT_CLEAR	(2 << 28)
+#define        ATMEL_TC_BEEVT_TOGGLE	(3 << 28)
+#define     ATMEL_TC_BSWTRG	(3 << 30)	/* software trigger changes TIOB */
+#define        ATMEL_TC_BSWTRG_NONE	(0 << 30)
+#define        ATMEL_TC_BSWTRG_SET	(1 << 30)
+#define        ATMEL_TC_BSWTRG_CLEAR	(2 << 30)
+#define        ATMEL_TC_BSWTRG_TOGGLE	(3 << 30)
+
+#define ATMEL_TC_CV	0x10		/* counter Value */
+#define ATMEL_TC_RA	0x14		/* register A */
+#define ATMEL_TC_RB	0x18		/* register B */
+#define ATMEL_TC_RC	0x1c		/* register C */
+
+#define ATMEL_TC_SR	0x20		/* status (read-only) */
+/* Status-only flags */
+#define     ATMEL_TC_CLKSTA	(1 << 16)	/* clock enabled */
+#define     ATMEL_TC_MTIOA	(1 << 17)	/* TIOA mirror */
+#define     ATMEL_TC_MTIOB	(1 << 18)	/* TIOB mirror */
+
+#define ATMEL_TC_IER	0x24		/* interrupt enable (write-only) */
+#define ATMEL_TC_IDR	0x28		/* interrupt disable (write-only) */
+#define ATMEL_TC_IMR	0x2c		/* interrupt mask (read-only) */
+
+/* Status and IRQ flags */
+#define     ATMEL_TC_COVFS	(1 <<  0)	/* counter overflow */
+#define     ATMEL_TC_LOVRS	(1 <<  1)	/* load overrun */
+#define     ATMEL_TC_CPAS	(1 <<  2)	/* RA compare */
+#define     ATMEL_TC_CPBS	(1 <<  3)	/* RB compare */
+#define     ATMEL_TC_CPCS	(1 <<  4)	/* RC compare */
+#define     ATMEL_TC_LDRAS	(1 <<  5)	/* RA loading */
+#define     ATMEL_TC_LDRBS	(1 <<  6)	/* RB loading */
+#define     ATMEL_TC_ETRGS	(1 <<  7)	/* external trigger */
+
+#endif
-- 
1.5.4.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH] atmel_tc clocksource/clockevent code
  2008-03-04 13:07 [PATCH] atmel_tc library Haavard Skinnemoen
@ 2008-03-04 13:07 ` Haavard Skinnemoen
  2008-03-04 19:42   ` Remy Bohmer
  0 siblings, 1 reply; 10+ messages in thread
From: Haavard Skinnemoen @ 2008-03-04 13:07 UTC (permalink / raw)
  To: akpm
  Cc: LKML, David Brownell, David Brownell, Haavard Skinnemoen,
	Nicolas Ferre, Andrew Victor, john stultz, Thomas Gleixner

From: David Brownell <david-b@pacbell.net>

Clocksource and clockevent device based on the Atmel TC blocks.

The clockevent device handles both periodic and oneshot modes, so this
enables NO_HZ and high res timers on some platforms that previously
couldn't use those mechanisms.

This works on both AVR32 and AT91 chips, given relevant patches for
tclib support (always) and clockevents (or else this will only look
like a higher precision clocksource).  It's an updated and modularized
version of an AT91-only patch that has circulated for some time now.

Changes relative to the original patch:
  * Update to use new tclib API
  * Replace open-coded do-while loop using goto with a real do-while loop
  * Minor irq handler optimization: Load register base address from
    dev_id instead of a global variable.
  * Aggressively turn off clocks when the clockevent isn't being used
  * Include the clockevent code on AT91RM9200 as well. The rating is
    lower than the System Timer, so the clock will usually stay off.
  * Don't assume that the number of clocks is always equal to the
    number of irqs.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
Cc: Andrew Victor <linux@maxim.org.za>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
This patch is meant to replace atmel_tc-clocksource-clockevent-code.patch

 drivers/clocksource/Makefile     |    1 +
 drivers/clocksource/tcb_clksrc.c |  305 ++++++++++++++++++++++++++++++++++++++
 drivers/misc/Kconfig             |   25 +++
 3 files changed, 331 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clocksource/tcb_clksrc.c

diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index a522254..1525882 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_ATMEL_TCB_CLKSRC)	+= tcb_clksrc.o
 obj-$(CONFIG_X86_CYCLONE_TIMER)	+= cyclone.o
 obj-$(CONFIG_X86_PM_TIMER)	+= acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)	+= scx200_hrt.o
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
new file mode 100644
index 0000000..17facda
--- /dev/null
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -0,0 +1,305 @@
+#include <linux/init.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/atmel_tc.h>
+
+
+/*
+ * We're configured to use a specific TC block, one that's not hooked
+ * up to external hardware, to provide a time solution:
+ *
+ *   - Two channels combine to create a free-running 32 bit counter
+ *     with a base rate of 5+ MHz, packaged as a clocksource (with
+ *     resolution better than 200 nsec).
+ *
+ *   - The third channel may be used to provide a 16-bit clockevent
+ *     source, used in either periodic or oneshot mode.  This runs
+ *     at 32 KiHZ, and can handle delays of up to two seconds.
+ *
+ * A boot clocksource and clockevent source are also currently needed,
+ * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
+ * this code can be used when init_timers() is called, well before most
+ * devices are set up.  (Some low end AT91 parts, which can run uClinux,
+ * have only the timers in one TC block... they currently don't support
+ * the tclib code, because of that initialization issue.)
+ *
+ * REVISIT behavior during system suspend states... we should disable
+ * all clocks and save the power.  Easily done for clockevent devices,
+ * but clocksources won't necessarily get the needed notifications.
+ * For deeper system sleep states, this will be mandatory...
+ */
+
+static void __iomem *tcaddr;
+
+static cycle_t tc_get_cycles(void)
+{
+	unsigned long	flags;
+	u32		lower, upper;
+
+	raw_local_irq_save(flags);
+	do {
+		upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV));
+		lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
+	} while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)));
+
+	raw_local_irq_restore(flags);
+	return (upper << 16) | lower;
+}
+
+static struct clocksource clksrc = {
+	.name           = "tcb_clksrc",
+	.rating         = 200,
+	.read           = tc_get_cycles,
+	.mask           = CLOCKSOURCE_MASK(32),
+	.shift          = 18,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
+struct tc_clkevt_device {
+	struct clock_event_device	clkevt;
+	struct clk			*clk;
+	void __iomem			*regs;
+};
+
+static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
+{
+	return container_of(clkevt, struct tc_clkevt_device, clkevt);
+}
+
+/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
+ * because using one of the divided clocks would usually mean the
+ * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
+ *
+ * A divided clock could be good for high resolution timers, since
+ * 30.5 usec resolution can seem "low".
+ */
+static u32 timer_clock;
+
+static void tc_mode(enum clock_event_mode m, struct clock_event_device *d)
+{
+	struct tc_clkevt_device *tcd = to_tc_clkevt(d);
+	void __iomem		*regs = tcd->regs;
+
+	if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC
+			|| tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) {
+		__raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR));
+		__raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
+		clk_disable(tcd->clk);
+	}
+
+	switch (m) {
+
+	/* By not making the gentime core emulate periodic mode on top
+	 * of oneshot, we get lower overhead and improved accuracy.
+	 */
+	case CLOCK_EVT_MODE_PERIODIC:
+		clk_enable(tcd->clk);
+
+		/* slow clock, count up to RC, then irq and restart */
+		__raw_writel(timer_clock
+				| ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
+				regs + ATMEL_TC_REG(2, CMR));
+		__raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
+
+		/* Enable clock and interrupts on RC compare */
+		__raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
+
+		/* go go gadget! */
+		__raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
+				regs + ATMEL_TC_REG(2, CCR));
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+		clk_enable(tcd->clk);
+
+		/* slow clock, count up to RC, then irq and stop */
+		__raw_writel(timer_clock | ATMEL_TC_CPCSTOP
+				| ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
+				regs + ATMEL_TC_REG(2, CMR));
+		__raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
+
+		/* set_next_event() configures and starts the timer */
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int tc_next_event(unsigned long delta, struct clock_event_device *d)
+{
+	__raw_writel(delta, tcaddr + ATMEL_TC_REG(2, RC));
+
+	/* go go gadget! */
+	__raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
+			tcaddr + ATMEL_TC_REG(2, CCR));
+	return 0;
+}
+
+static struct tc_clkevt_device clkevt = {
+	.clkevt	= {
+		.name		= "tc_clkevt",
+		.features	= CLOCK_EVT_FEAT_PERIODIC
+					| CLOCK_EVT_FEAT_ONESHOT,
+		.shift		= 32,
+		/* Should be lower than at91rm9200's system timer */
+		.rating		= 125,
+		.cpumask	= CPU_MASK_CPU0,
+		.set_next_event	= tc_next_event,
+		.set_mode	= tc_mode,
+	},
+};
+
+static irqreturn_t ch2_irq(int irq, void *handle)
+{
+	struct tc_clkevt_device	*dev = handle;
+	unsigned int		sr;
+
+	sr = __raw_readl(dev->regs + ATMEL_TC_REG(2, SR));
+	if (sr & ATMEL_TC_CPCS) {
+		dev->clkevt.event_handler(&dev->clkevt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static struct irqaction tc_irqaction = {
+	.name		= "tc_clkevt",
+	.flags		= IRQF_TIMER | IRQF_DISABLED,
+	.handler	= ch2_irq,
+};
+
+static void __init setup_clkevents(struct atmel_tc *tc,
+		struct clk *t0_clk, int clk32k_divisor_idx)
+{
+	struct platform_device *pdev = tc->pdev;
+	struct clk *t2_clk = tc->clk[2];
+	int irq = tc->irq[2];
+
+	clkevt.regs = tc->regs;
+	clkevt.clk = t2_clk;
+	tc_irqaction.dev_id = &clkevt;
+
+	timer_clock = clk32k_divisor_idx;
+
+	clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift);
+	clkevt.clkevt.max_delta_ns
+		= clockevent_delta2ns(0xffff, &clkevt.clkevt);
+	clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
+
+	setup_irq(irq, &tc_irqaction);
+
+	clockevents_register_device(&clkevt.clkevt);
+}
+
+#else /* !CONFIG_GENERIC_CLOCKEVENTS */
+
+static void __init setup_clkevents(struct atmel_tc *tc,
+		struct clk *t0_clk, int clk32k_divisor_idx)
+{
+	/* NOTHING */
+}
+
+#endif
+
+static int __init tcb_clksrc_init(void)
+{
+	static char bootinfo[] __initdata
+		= KERN_DEBUG "%s: tc%d at %d.%03d MHz\n";
+
+	struct platform_device *pdev;
+	struct atmel_tc *tc;
+	struct clk *t0_clk, *t1_clk;
+	u32 rate, divided_rate = 0;
+	int best_divisor_idx = -1;
+	int clk32k_divisor_idx = -1;
+	int i;
+
+	tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name);
+	if (!tc) {
+		pr_debug("can't alloc TC for clocksource\n");
+		return -ENODEV;
+	}
+	tcaddr = tc->regs;
+	pdev = tc->pdev;
+
+	t0_clk = tc->clk[0];
+	clk_enable(t0_clk);
+
+	/* How fast will we be counting?  Pick something over 5 MHz.  */
+	rate = (u32) clk_get_rate(t0_clk);
+	for (i = 0; i < 5; i++) {
+		unsigned divisor = atmel_tc_divisors[i];
+		unsigned tmp;
+
+		/* remember 32 KiHz clock for later */
+		if (!divisor) {
+			clk32k_divisor_idx = i;
+			continue;
+		}
+
+		tmp = rate / divisor;
+		pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
+		if (best_divisor_idx > 0) {
+			if (tmp < 5 * 1000 * 1000)
+				continue;
+		}
+		divided_rate = tmp;
+		best_divisor_idx = i;
+	}
+
+	clksrc.mult = clocksource_hz2mult(divided_rate, clksrc.shift);
+
+	printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK,
+			divided_rate / 1000000,
+			((divided_rate + 500000) % 1000000) / 1000);
+
+	/* tclib will give us three clocks no matter what the
+	 * underlying platform supports.
+	 */
+	clk_enable(tc->clk[1]);
+
+	/* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
+	__raw_writel(best_divisor_idx			/* likely divide-by-8 */
+			| ATMEL_TC_WAVE
+			| ATMEL_TC_WAVESEL_UP		/* free-run */
+			| ATMEL_TC_ACPA_SET		/* TIOA0 rises at 0 */
+			| ATMEL_TC_ACPC_CLEAR,		/* (duty cycle 50%) */
+			tcaddr + ATMEL_TC_REG(0, CMR));
+	__raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
+	__raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
+	__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));	/* no irqs */
+	__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
+
+	/* channel 1:  waveform mode, input TIOA0 */
+	__raw_writel(ATMEL_TC_XC1			/* input: TIOA0 */
+			| ATMEL_TC_WAVE
+			| ATMEL_TC_WAVESEL_UP,		/* free-run */
+			tcaddr + ATMEL_TC_REG(1, CMR));
+	__raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));	/* no irqs */
+	__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
+
+	/* chain channel 0 to channel 1, then reset all the timers */
+	__raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
+	__raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+
+	/* and away we go! */
+	clocksource_register(&clksrc);
+
+	/* channel 2:  periodic and oneshot timer support */
+	setup_clkevents(tc, t0_clk, clk32k_divisor_idx);
+
+	return 0;
+}
+arch_initcall(tcb_clksrc_init);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b3ba681..4cf928e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -30,6 +30,31 @@ config ATMEL_TCLIB
 	  blocks found on many Atmel processors.  This facilitates using
 	  these blocks by different drivers despite processor differences.
 
+config ATMEL_TCB_CLKSRC
+	bool "TC Block Clocksource"
+	depends on ATMEL_TCLIB && GENERIC_TIME
+	default y
+	help
+	  Select this to get a high precision clocksource based on a
+	  TC block with a 5+ MHz base clock rate.  Two timer channels
+	  are combined to make a single 32-bit timer.
+
+	  When GENERIC_CLOCKEVENTS is defined, the third timer channel
+	  may be used as a clock event device supporting oneshot mode
+	  (delays of up to two seconds) based on the 32 KiHz clock.
+
+config ATMEL_TCB_CLKSRC_BLOCK
+	int
+	depends on ATMEL_TCB_CLKSRC
+	prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X
+	default 0
+	range 0 1
+	help
+	  Some chips provide more than one TC block, so you have the
+	  choice of which one to use for the clock framework.  The other
+	  TC can be used for other purposes, such as PWM generation and
+	  interval timing.
+
 config IBM_ASM
 	tristate "Device driver for IBM RSA service processor"
 	depends on X86 && PCI && INPUT && EXPERIMENTAL
-- 
1.5.4.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] atmel_tc clocksource/clockevent code
  2008-03-04 13:07 ` [PATCH] atmel_tc clocksource/clockevent code Haavard Skinnemoen
@ 2008-03-04 19:42   ` Remy Bohmer
  2008-03-04 20:47     ` David Brownell
  0 siblings, 1 reply; 10+ messages in thread
From: Remy Bohmer @ 2008-03-04 19:42 UTC (permalink / raw)
  To: Haavard Skinnemoen
  Cc: akpm, LKML, David Brownell, David Brownell, Nicolas Ferre,
	Andrew Victor, john stultz, Thomas Gleixner

Hello Haavard,

Good work on improving this patch. I am very happy with the accurate
clocksource devices, I use the patches from David for quite some time
now.

But, I noticed this comment in the patch:

>  +/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
>  + * because using one of the divided clocks would usually mean the
>  + * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
>  + *
>  + * A divided clock could be good for high resolution timers, since
>  + * 30.5 usec resolution can seem "low".

I want to comment on that.
I noticed that on rm9200 the timer interrupt handler itself can cost
about 50us to more than 100usec in itself (measured through ETM
trace), combined with a worst case interrupt latency of about 75us.
So, a higher resolution than 30usec is useless on these cores, and
setting timers on a frequency that high will just choke the processor
in only handling timers...

To prevent applications to start timers too fast after each other, it
is even useful to limit the granularity of these timers, and to get
them aligned so that they can be handled on just 1 interrupt. (Hmm,
this sounds like the behavior of a ticking kernel ;-))

This is the reason why I stopped using the High-resolution timer
framework on these cores. It just overloads the CPU too much when
several applications use independent timers that are not in sync with
each other. A ticking kernel is therefor more CPU-load friendly...


Kind Regards,

Remy

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] atmel_tc clocksource/clockevent code
  2008-03-04 19:42   ` Remy Bohmer
@ 2008-03-04 20:47     ` David Brownell
  2008-03-05 11:17       ` Remy Bohmer
  0 siblings, 1 reply; 10+ messages in thread
From: David Brownell @ 2008-03-04 20:47 UTC (permalink / raw)
  To: Remy Bohmer
  Cc: Haavard Skinnemoen, akpm, LKML, David Brownell, Nicolas Ferre,
	Andrew Victor, john stultz, Thomas Gleixner

On Tuesday 04 March 2008, Remy Bohmer wrote:
> >  +/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
> >  + * because using one of the divided clocks would usually mean the
> >  + * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
> >  + *
> >  + * A divided clock could be good for high resolution timers, since
> >  + * 30.5 usec resolution can seem "low".
> 
> I want to comment on that.
>
> I noticed that on rm9200 the timer interrupt handler itself can cost
> about 50us to more than 100usec in itself (measured through ETM
> trace), combined with a worst case interrupt latency of about 75us.

Could you elaborate on where that 50-100 usec gets spent?  Does
the same issue happpen with the $SUBJECT patch (if you tweak the
clocksource ratings to use its clockevents on rm9200)?

I'd not think the timer IRQ logic accounts for much of that time,
and the rest of the instruction cycles would seem to be either
in genirq or gentime.  Unless the issue is that accessing that
particular hardware is slow, with clockdomain crossing etc ...
or that AT91 has way too many handlers sitting on IRQ-1.

If it's a gentime or genirq issue, that's somewhat amenable to
fixing ... and it would also impact the $SUBJECT patch both on
other AT91 ARM9 cores and on the AVR32 AP7 cores.


> So, a higher resolution than 30usec is useless on these cores, and
> setting timers on a frequency that high will just choke the processor
> in only handling timers...

Should the min_delta_ns be increased in at91rm9200_time.c then?
Right now, as you probably recall, it's at the lowest value
needed for correctness:  a smidgeon over two ticks (~ 72 nsec).

- Dave


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] atmel_tc clocksource/clockevent code
  2008-03-04 20:47     ` David Brownell
@ 2008-03-05 11:17       ` Remy Bohmer
  2008-03-05 13:06         ` David Brownell
  2008-03-05 16:45         ` Thomas Gleixner
  0 siblings, 2 replies; 10+ messages in thread
From: Remy Bohmer @ 2008-03-05 11:17 UTC (permalink / raw)
  To: David Brownell
  Cc: Haavard Skinnemoen, akpm, LKML, David Brownell, Nicolas Ferre,
	Andrew Victor, john stultz, Thomas Gleixner

[-- Attachment #1: Type: text/plain, Size: 3217 bytes --]

Hello David,

> Could you elaborate on where that 50-100 usec gets spent?

Attached I have put a screendump of my ETM debugger. It shows a
complete flow of kernel function-calls of what happens on a timer
interrupt. In this example the complete sequence takes about 154 us.
Notice that the ETM is non-intrusive, and that the times are real and
accurate in this trace. (you can even see the effects of CPU-caches,
sometimes the same code just runs faster)
It is based on 2.6.23.12-rt14, with a ticking kernel, I have attached
the .config of the kernel under trace also. The CPU is running at
160/80Mhz.
I have some custom patches to the kernel, but none of them effect this
particular trace.

> Does the same issue happpen with the $SUBJECT patch (if you tweak the
>  clocksource ratings to use its clockevents on rm9200)?

not tested yet, but I will generate a trace for it, I will post it later.

>  I'd not think the timer IRQ logic accounts for much of that time,
>  and the rest of the instruction cycles would seem to be either
>  in genirq or gentime.

There is more to it than just the genIRQ mechanism. The softirqs are
kicked, the scheduler is triggered and so on. It is a waterfall of
events that happen, just by having a timer interrupt.

> Unless the issue is that accessing that
>  particular hardware is slow, with clockdomain crossing etc ...
>  or that AT91 has way too many handlers sitting on IRQ-1.
>  If it's a gentime or genirq issue, that's somewhat amenable to
>  fixing ... and it would also impact the $SUBJECT patch both on
>  other AT91 ARM9 cores and on the AVR32 AP7 cores.

>  > So, a higher resolution than 30usec is useless on these cores, and
>  > setting timers on a frequency that high will just choke the processor
>  > in only handling timers...
> Should the min_delta_ns be increased in at91rm9200_time.c then?

Maybe it should be configurable for these kinds of CPUs?

If a CPU is infinite fast, one could probably want a HRT resolution of zero.
But, no CPUs are that fast, and I assume there is always a need to get
a good balance between timer resolution compared to CPU load.
We probably do not want to cause a DoS by building some application
that starts (periodic) timers that fast, that the CPU is doing nothing
more than just that. To me, it appears that the HRT framework is going
that route here. It seems to me now, that if it is technically
possible to create a microsec accurate timer-framework, we make them,
regardless of it fits the rest of the system.
Notice that I also fell in this pitfall while using HRT, and I only
wanted an application that made a 1ms accurate timer... Other
processes/daemons in the system also uses timers, which eventually
resulted in intervals in the sub-millisec range, and thus due to the
overhead that will bring tot the system, the CPU-load just goes
sky-high, doing actually nothing really special.

So, hires timestamps -> really really welcome.
hires timers -> there should be a (configurable) minimal resolution
that fits the hardware to not overload the CPU.

>  Right now, as you probably recall, it's at the lowest value
>  needed for correctness:  a smidgeon over two ticks (~ 72 nsec).

I remember...

Kind Regards,

Remy

[-- Attachment #2: trace-timer-interrupt-rm9200.png --]
[-- Type: image/png, Size: 126791 bytes --]

[-- Attachment #3: .config --]
[-- Type: application/octet-stream, Size: 18005 bytes --]

#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.23.12-rt14
# Wed Mar  5 09:09:39 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
# CONFIG_NO_IOPORT is not set
CONFIG_GENERIC_HARDIRQS=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ZONE_DMA=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"

#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
# CONFIG_RADIX_TREE_CONCURRENT is not set
CONFIG_EMBEDDED=y
# CONFIG_UID16 is not set
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_EVENTFD=y
# CONFIG_SHMEM is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
CONFIG_TINY_SHMEM=y
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
# CONFIG_BLK_DEV_BSG is not set

#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"

#
# System Type
#
# CONFIG_ARCH_AAEC2000 is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
CONFIG_ARCH_AT91=y
# CONFIG_ARCH_CLPS7500 is not set
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
# CONFIG_ARCH_IXP23XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_L7200 is not set
# CONFIG_ARCH_KS8695 is not set
# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_MXC is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set

#
# Boot options
#

#
# Power management
#

#
# Atmel AT91 System-on-Chip
#
CONFIG_ARCH_AT91RM9200=y
# CONFIG_ARCH_AT91SAM9260 is not set
# CONFIG_ARCH_AT91SAM9261 is not set
# CONFIG_ARCH_AT91SAM9263 is not set
# CONFIG_ARCH_AT91SAM9RL is not set

#
# AT91RM9200 Board Type
#
# CONFIG_MACH_ONEARM is not set
# CONFIG_ARCH_AT91RM9200DK is not set
# CONFIG_MACH_AT91RM9200EK is not set
CONFIG_MACH_OCEARMTEST=y
# CONFIG_MACH_CSB337 is not set
# CONFIG_MACH_CSB637 is not set
# CONFIG_MACH_CARMEVA is not set
# CONFIG_MACH_ATEB9200 is not set
# CONFIG_MACH_KB9200 is not set
# CONFIG_MACH_PICOTUX2XX is not set
# CONFIG_MACH_KAFA is not set
# CONFIG_MACH_CHUB is not set
# CONFIG_MACH_HOMEMATIC is not set
# CONFIG_MACH_ECBAT91 is not set
# CONFIG_MACH_SWEDATMS is not set

#
# AT91 Board Options
#

#
# AT91 Feature Selections
#
# CONFIG_AT91_PROGRAMMABLE_CLOCKS is not set
CONFIG_ATMEL_TCLIB=y
CONFIG_AT91_TC_CLOCKSOURCE=y
CONFIG_AT91_TIMER_HZ=100

#
# Processor Type
#
CONFIG_CPU_32=y
CONFIG_CPU_ARM920T=y
CONFIG_CPU_32v4T=y
CONFIG_CPU_ABRT_EV4T=y
CONFIG_CPU_CACHE_V4WT=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y

#
# Processor Features
#
# CONFIG_ARM_THUMB is not set
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
# CONFIG_OUTER_CACHE is not set

#
# Bus support
#
# CONFIG_PCI_SYSCALL is not set
# CONFIG_ARCH_SUPPORTS_MSI is not set

#
# PCCARD (PCMCIA/CardBus) support
#
# CONFIG_PCCARD is not set

#
# Kernel Features
#
# CONFIG_TICK_ONESHOT is not set
# CONFIG_NO_HZ is not set
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT_DESKTOP is not set
CONFIG_PREEMPT_RT=y
CONFIG_PREEMPT=y
CONFIG_PREEMPT_SOFTIRQS=y
CONFIG_PREEMPT_HARDIRQS=y
CONFIG_PREEMPT_BKL=y
# CONFIG_CLASSIC_RCU is not set
CONFIG_PREEMPT_RCU=y
# CONFIG_PREEMPT_RCU_BOOST is not set
# CONFIG_RCU_TRACE is not set
CONFIG_HZ=100
CONFIG_AEABI=y
# CONFIG_OABI_COMPAT is not set
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4096
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
CONFIG_LEDS=y
CONFIG_LEDS_CPU=y
CONFIG_ALIGNMENT_TRAP=y

#
# Boot options
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CMDLINE=""
# CONFIG_XIP_KERNEL is not set
# CONFIG_KEXEC is not set

#
# Floating point emulation
#

#
# At least one emulation must be selected
#

#
# Userspace binary formats
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_AOUT is not set
# CONFIG_BINFMT_MISC is not set

#
# Power management options
#
# CONFIG_PM is not set
CONFIG_SUSPEND_UP_POSSIBLE=y

#
# Networking
#
CONFIG_NET=y

#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_DHCP is not set
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_DIAG is not set
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set

#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set

#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set

#
# Wireless
#
# CONFIG_CFG80211 is not set
# CONFIG_WIRELESS_EXT is not set
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set

#
# Device Drivers
#

#
# Oce Custom Driver support
#
CONFIG_OCE_ARMIO=y
CONFIG_OCE_ARMIO_TC_BLOCK_TIME_BASE=y
CONFIG_OCE_ARMIO_DEBUG_ENABLED=y
# CONFIG_OCE_ARMIO_DEBUG_LEVEL_RW is not set
# CONFIG_OCE_ARMIO_DEBUG_LEVEL_IRQ is not set
# CONFIG_OCE_ARMIO_DEBUG_LEVEL_OTHER is not set

#
# Rose RTS support
#
CONFIG_ROSE_RTS=y
# CONFIG_ROSE_RTS_DEBUG is not set

#
# Generic Driver Options
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set

#
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set

#
# RAM/ROM/Flash chip drivers
#
CONFIG_MTD_CFI=y
# CONFIG_MTD_JEDECPROBE is not set
CONFIG_MTD_GEN_PROBE=y
# CONFIG_MTD_CFI_ADV_OPTIONS is not set
CONFIG_MTD_MAP_BANK_WIDTH_1=y
CONFIG_MTD_MAP_BANK_WIDTH_2=y
CONFIG_MTD_MAP_BANK_WIDTH_4=y
# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_CFI_STAA=y
CONFIG_MTD_CFI_UTIL=y
CONFIG_MTD_RAM=y
CONFIG_MTD_ROM=y
CONFIG_MTD_ABSENT=y

#
# Mapping drivers for chip access
#
CONFIG_MTD_COMPLEX_MAPPINGS=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_PHYSMAP_START=0x8000000
CONFIG_MTD_PHYSMAP_LEN=0
CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_MTD_ARM_INTEGRATOR is not set
# CONFIG_MTD_PLATRAM is not set

#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLOCK2MTD is not set

#
# Disk-On-Chip Device Drivers
#
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
# CONFIG_MTD_NAND is not set
# CONFIG_MTD_ONENAND is not set

#
# UBI - Unsorted block images
#
# CONFIG_MTD_UBI is not set
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set

#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_ATA is not set
# CONFIG_MD is not set
CONFIG_NETDEVICES=y
# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_PHYLIB is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
CONFIG_ARM_AT91_ETHER=y
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set

#
# Wireless LAN
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_ISDN is not set

#
# Input device support
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_POLLDEV is not set

#
# Userland interfaces
#
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set

#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set

#
# Hardware I/O ports
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set

#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set

#
# Serial drivers
#
# CONFIG_SERIAL_8250 is not set

#
# Non-8250 serial port support
#
CONFIG_SERIAL_ATMEL=y
CONFIG_SERIAL_ATMEL_CONSOLE=y
CONFIG_SERIAL_ATMEL_PDC=y
# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_IPMI_HANDLER is not set
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_NVRAM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
# CONFIG_RMEM is not set
# CONFIG_ALLOC_RTSJ_MEM is not set
# CONFIG_AT91_SPI is not set
# CONFIG_I2C is not set

#
# SPI support
#
CONFIG_SPI=y
# CONFIG_SPI_MASTER is not set

#
# SPI Slave Controller Drivers
#
CONFIG_CEI=y
# CONFIG_W1 is not set
# CONFIG_HWMON is not set
# CONFIG_MISC_DEVICES is not set

#
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set
# CONFIG_NEW_LEDS is not set

#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
# CONFIG_DVB_CORE is not set
# CONFIG_DAB is not set

#
# Graphics support
#
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set

#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
# CONFIG_FB is not set

#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y

#
# Sound
#
# CONFIG_SOUND is not set
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_MMC is not set
CONFIG_RTC_LIB=y
# CONFIG_RTC_CLASS is not set

#
# DMA Engine support
#
# CONFIG_DMA_ENGINE is not set

#
# DMA Clients
#

#
# DMA Devices
#

#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
# CONFIG_EXT4DEV_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_INOTIFY is not set
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set

#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set

#
# DOS/FAT/NT Filesystems
#
# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_NTFS_FS is not set

#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set

#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
# CONFIG_JFFS2_SUMMARY is not set
CONFIG_JFFS2_FS_XATTR=y
CONFIG_JFFS2_FS_POSIX_ACL=y
CONFIG_JFFS2_FS_SECURITY=y
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set

#
# Network File Systems
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_SUNRPC_BIND34 is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set

#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y

#
# Native Language Support
#
# CONFIG_NLS is not set

#
# Distributed Lock Manager
#
# CONFIG_DLM is not set

#
# Profiling support
#
# CONFIG_PROFILING is not set

#
# Instrumentation Support
#
# CONFIG_IMMEDIATE is not set
CONFIG_MARKERS=y
CONFIG_LTT=y
CONFIG_LTT_TRACER=m
CONFIG_LTT_RELAY=m
CONFIG_LTT_SERIALIZE=m
# CONFIG_LTT_ALIGNMENT is not set
# CONFIG_LTT_HEARTBEAT is not set
# CONFIG_LTT_USERSPACE_GENERIC is not set
CONFIG_LTT_NETLINK_CONTROL=m
CONFIG_LTT_STATEDUMP=m

#
# Probes
#
CONFIG_LTT_PROBE_CORE=m
CONFIG_LTT_PROBE_FS=m
CONFIG_LTT_PROBE_KERNEL=m
CONFIG_LTT_PROBE_ARCH=m
CONFIG_LTT_PROBE_MM=m
CONFIG_LTT_PROBE_NET=m
CONFIG_LTT_PROBE_LIST=m

#
# Kernel hacking
#
CONFIG_PRINTK_TIME=y
CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_EVENT_TRACE is not set
# CONFIG_FUNCTION_TRACE is not set
# CONFIG_WAKEUP_TIMING is not set
# CONFIG_CRITICAL_PREEMPT_TIMING is not set
# CONFIG_CRITICAL_IRQSOFF_TIMING is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_FRAME_POINTER=y
CONFIG_DEBUG_USER=y

#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_CRYPTO is not set

#
# Library routines
#
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] atmel_tc clocksource/clockevent code
  2008-03-05 11:17       ` Remy Bohmer
@ 2008-03-05 13:06         ` David Brownell
  2008-03-05 16:45         ` Thomas Gleixner
  1 sibling, 0 replies; 10+ messages in thread
From: David Brownell @ 2008-03-05 13:06 UTC (permalink / raw)
  To: Remy Bohmer
  Cc: Haavard Skinnemoen, akpm, LKML, David Brownell, Nicolas Ferre,
	Andrew Victor, john stultz, Thomas Gleixner

On Wednesday 05 March 2008, Remy Bohmer wrote:
> Hello David,
> 
> > Could you elaborate on where that 50-100 usec gets spent?
> 
> Attached I have put a screendump of my ETM debugger. It shows a
> complete flow of kernel function-calls of what happens on a timer
> interrupt. In this example the complete sequence takes about 154 us.

Thanks -- this is quite informative.  (Presumably it'd look similar
using NO_HZ too:  hardly any overhead is hardware-specific.)

An ETM trace is really nice for this kind of stuff; it'd be nice
if such tech were more widely available!  (Built into most ARM cores
and all that ... but the hardware and software tools to access the
data aren't as available.)  


> Notice that the ETM is non-intrusive, and that the times are real and
> accurate in this trace. (you can even see the effects of CPU-caches,
> sometimes the same code just runs faster)

Yeah, the intrusive schemes (like automatic probe insertion) perturb
timings at this level.


> > Does the same issue happpen with the $SUBJECT patch (if you tweak the
> >  clocksource ratings to use its clockevents on rm9200)?
> 
> not tested yet, but I will generate a trace for it, I will post it later.

Based on how little of that time was spent in the rm9200 clockevent
code -- I'll be generous and call it 10 usec -- I'd can't imagine that
could make much of a real difference.


> There is more to it than just the genIRQ mechanism. The softirqs are
> kicked, the scheduler is triggered and so on. It is a waterfall of
> events that happen, just by having a timer interrupt.

Right.


> > Should the min_delta_ns be increased in at91rm9200_time.c then?
> 
> Maybe it should be configurable for these kinds of CPUs?

It shouldn't require tweaking individual clockevent devices, or
IMO be specific to e.g. lower powered CPUs ... but a global
min_delta_ns would be easy to implement, and might help.

That'd resemble what the init_timer_deferrable() mechanism
achieves, but the scale for bunching timers would be fine
not coarse.


> Notice that I also fell in this pitfall while using HRT, and I only
> wanted an application that made a 1ms accurate timer... Other
> processes/daemons in the system also uses timers, which eventually
> resulted in intervals in the sub-millisec range, and thus due to the
> overhead that will bring tot the system, the CPU-load just goes
> sky-high, doing actually nothing really special.

In your case, maybe a global min_delta_ns of 1000 * 1000 would
help ... combine with NO_HZ and you'd get the accuracy you need,
with reduced scheduling overhead.  Sound about right?

- Dave


> So, hires timestamps -> really really welcome.
> hires timers -> there should be a (configurable) minimal resolution
> that fits the hardware to not overload the CPU.
> 
> >  Right now, as you probably recall, it's at the lowest value
> >  needed for correctness:  a smidgeon over two ticks (~ 72 nsec).
> 
> I remember...
> 
> Kind Regards,
> 
> Remy
> 



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] atmel_tc clocksource/clockevent code
  2008-03-05 11:17       ` Remy Bohmer
  2008-03-05 13:06         ` David Brownell
@ 2008-03-05 16:45         ` Thomas Gleixner
  2008-03-05 21:14           ` David Brownell
  2008-03-05 22:35           ` Remy Bohmer
  1 sibling, 2 replies; 10+ messages in thread
From: Thomas Gleixner @ 2008-03-05 16:45 UTC (permalink / raw)
  To: Remy Bohmer
  Cc: David Brownell, Haavard Skinnemoen, akpm, LKML, David Brownell,
	Nicolas Ferre, Andrew Victor, john stultz

On Wed, 5 Mar 2008, Remy Bohmer wrote:
> Hello David,
> 
> > Could you elaborate on where that 50-100 usec gets spent?
> 
> Attached I have put a screendump of my ETM debugger. It shows a
> complete flow of kernel function-calls of what happens on a timer
> interrupt. In this example the complete sequence takes about 154 us.
> Notice that the ETM is non-intrusive, and that the times are real and
> accurate in this trace. (you can even see the effects of CPU-caches,
> sometimes the same code just runs faster)

Is there any chance to convert this to a text table? Following that
png is pretty hard.

> So, hires timestamps -> really really welcome.
> hires timers -> there should be a (configurable) minimal resolution
> that fits the hardware to not overload the CPU.

clockevents let you set a minimum delta already. This can be set at
runtime before registering the device.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] atmel_tc clocksource/clockevent code
  2008-03-05 16:45         ` Thomas Gleixner
@ 2008-03-05 21:14           ` David Brownell
  2008-03-05 22:35           ` Remy Bohmer
  1 sibling, 0 replies; 10+ messages in thread
From: David Brownell @ 2008-03-05 21:14 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Remy Bohmer, Haavard Skinnemoen, akpm, LKML, Nicolas Ferre,
	Andrew Victor, john stultz

On Wednesday 05 March 2008, Thomas Gleixner wrote:
> > So, hires timestamps -> really really welcome.
> > hires timers -> there should be a (configurable) minimal resolution
> > that fits the hardware to not overload the CPU.
> 
> clockevents let you set a minimum delta already. This can be set at
> runtime before registering the device.

But the overhead isn't specific to any given clockevent
device.  The same issue was reported on other ARMs.

The acceptable overhead is a function of system-specific
factors including load and CPU clock rate, not of a given
clockevent device.

I wouldn't think teaching multiple such drivers about such
issues could be better than having clockevents_program_event()
consider a system-specific lower bound ...

- Dave



==============
Add a "min_delta_ns" kernel parameter to help systems avoid excess
scheduling and timer overheads.  As with init_timer_deferrable(),
this batches timer IRQs to reduce those overheads.

For example, on one ARM9 platform the timer IRQ takes 2 usec, but the
system then needs over 150 usec to handle scheduler-related tasks.
On such a system, applications using many high resolution timers can
work better if min_delta_ns is used to avoid scheduling timer IRQs
so often that no other work gets done.

---
 Documentation/kernel-parameters.txt |    7 +++++++
 kernel/time/clockevents.c           |   15 +++++++++++++++
 2 files changed, 22 insertions(+)

--- a/Documentation/kernel-parameters.txt	2008-02-23 11:36:13.000000000 -0800
+++ b/Documentation/kernel-parameters.txt	2008-03-05 12:58:20.000000000 -0800
@@ -1146,6 +1146,13 @@ and is between 256 and 4096 characters. 
 
 	mga=		[HW,DRM]
 
+	min_delta_ns=n	[GENERIC_TIME] Defines the minimum amount of time
+			that oneshot clockevent sources will be asked to
+			sleep.  This is measured in nanoseconds, and may be
+			overridden by the clockevent device.  You probably
+			want this number to be more than your system's timer
+			IRQ overhead.
+
 	mousedev.tap_time=
 			[MOUSE] Maximum time between finger touching and
 			leaving touchpad surface for touch to be considered
--- a/kernel/time/clockevents.c	2008-02-10 15:48:29.000000000 -0800
+++ b/kernel/time/clockevents.c	2008-03-05 12:38:14.000000000 -0800
@@ -29,6 +29,18 @@ static RAW_NOTIFIER_HEAD(clockevents_cha
 /* Protection for the above */
 static DEFINE_SPINLOCK(clockevents_lock);
 
+/* This is the lower bound on oneshot timer intervals; setting its
+ * value too low can maintain HRT overhead at objectionable levels.
+ */
+static unsigned long min_delta_ns;
+
+static int __init set_min_delta_ns(char *str)
+{
+	simple_strtoul(str, NULL, 0);
+	return 1;
+}
+__setup("min_delta_ns", set_min_delta_ns);
+
 /**
  * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
  * @latch:	value to convert
@@ -98,6 +110,9 @@ int clockevents_program_event(struct clo
 	if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
 		return 0;
 
+	if (delta < min_delta_ns)
+		delta = min_delta_ns;
+
 	if (delta > dev->max_delta_ns)
 		delta = dev->max_delta_ns;
 	if (delta < dev->min_delta_ns)

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] atmel_tc clocksource/clockevent code
  2008-03-05 16:45         ` Thomas Gleixner
  2008-03-05 21:14           ` David Brownell
@ 2008-03-05 22:35           ` Remy Bohmer
  2008-03-05 22:52             ` Thomas Gleixner
  1 sibling, 1 reply; 10+ messages in thread
From: Remy Bohmer @ 2008-03-05 22:35 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: David Brownell, Haavard Skinnemoen, akpm, LKML, David Brownell,
	Nicolas Ferre, Andrew Victor, john stultz

Hello Thomas,

>  > Attached I have put a screendump of my ETM debugger. It shows a
>  > complete flow of kernel function-calls of what happens on a timer
>  > interrupt. In this example the complete sequence takes about 154 us.
>  > Notice that the ETM is non-intrusive, and that the times are real and
>  > accurate in this trace. (you can even see the effects of CPU-caches,
>  > sometimes the same code just runs faster)
>
> Is there any chance to convert this to a text table? Following that
>  png is pretty hard.

I will see what I can do, but this was the easiest way (it was just a
print-screen;-) )
But, will text-dump make it more clear? It could also contain the time
each assembler instruction will take behind the routines...
But, I will look into that tomorrow. (approx. 12 hours from now)

>  > So, hires timestamps -> really really welcome.
>  > hires timers -> there should be a (configurable) minimal resolution
>  > that fits the hardware to not overload the CPU.
>
> clockevents let you set a minimum delta already. This can be set at
>  runtime before registering the device.

But, I want to expose a bigger risk here.
Apparently it is possible that a non privileged user can overload the
system easily, by starting a high frequency periodic timer. The system
will be that busy handling that timer that the system stops
responding, thus it will result in some kind of Denial-of-Service
situation, even on X86.

I think that there should be a hard limit to prevent starting timers
at higher frequencies than they can be handled by the platform,
included the scheduler overhead.

David has proposed a solution via the kernel-commandline, but I think
it should be a hard coded limit, to prevent that it is forgotten by
the end-user to put it on the kernel-cmd-line. Maybe a sub-option that
gets visible when HRT is enabled in menuconfig, this option should be
default very conservative, and the user should think about the lower
bound he really needs before he really gets HRT enabled.

What do you think of this? (I can propose a patch for this tomorrow)


Kind Regards,

Remy

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] atmel_tc clocksource/clockevent code
  2008-03-05 22:35           ` Remy Bohmer
@ 2008-03-05 22:52             ` Thomas Gleixner
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Gleixner @ 2008-03-05 22:52 UTC (permalink / raw)
  To: Remy Bohmer
  Cc: David Brownell, Haavard Skinnemoen, akpm, LKML, David Brownell,
	Nicolas Ferre, Andrew Victor, john stultz

On Wed, 5 Mar 2008, Remy Bohmer wrote:
> Hello Thomas,
> 
> >  > Attached I have put a screendump of my ETM debugger. It shows a
> >  > complete flow of kernel function-calls of what happens on a timer
> >  > interrupt. In this example the complete sequence takes about 154 us.
> >  > Notice that the ETM is non-intrusive, and that the times are real and
> >  > accurate in this trace. (you can even see the effects of CPU-caches,
> >  > sometimes the same code just runs faster)
> >
> > Is there any chance to convert this to a text table? Following that
> >  png is pretty hard.
> 
> I will see what I can do, but this was the easiest way (it was just a
> print-screen;-) )
> But, will text-dump make it more clear? It could also contain the time
> each assembler instruction will take behind the routines...

text files can be parsed by scripts :)

> But, I will look into that tomorrow. (approx. 12 hours from now)

thnx
 
> >  > So, hires timestamps -> really really welcome.
> >  > hires timers -> there should be a (configurable) minimal resolution
> >  > that fits the hardware to not overload the CPU.
> >
> > clockevents let you set a minimum delta already. This can be set at
> >  runtime before registering the device.
> 
> But, I want to expose a bigger risk here.
> Apparently it is possible that a non privileged user can overload the
> system easily, by starting a high frequency periodic timer. The system
> will be that busy handling that timer that the system stops
> responding, thus it will result in some kind of Denial-of-Service
> situation, even on X86.

Wrong. The rearm condition is that the task is rescheduled. On any
platform.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2008-03-05 23:01 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-04 13:07 [PATCH] atmel_tc library Haavard Skinnemoen
2008-03-04 13:07 ` [PATCH] atmel_tc clocksource/clockevent code Haavard Skinnemoen
2008-03-04 19:42   ` Remy Bohmer
2008-03-04 20:47     ` David Brownell
2008-03-05 11:17       ` Remy Bohmer
2008-03-05 13:06         ` David Brownell
2008-03-05 16:45         ` Thomas Gleixner
2008-03-05 21:14           ` David Brownell
2008-03-05 22:35           ` Remy Bohmer
2008-03-05 22:52             ` Thomas Gleixner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).