2011-06-09 13:08:31

by Thomas Gleixner

[permalink] [raw]
Subject: [patch 1/5] i8253: Create common clockevent implementation

arm, mips and x86 implement i8253 based clockevents. All the same code
copied. Create a common implementation in drivers/clocksource/i8253.c.

About time to rename drivers/clocksource/ to something else.

Signed-off-by: Thomas Gleixner <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: Russell King <[email protected]>

---
drivers/clocksource/Kconfig | 5 +-
drivers/clocksource/i8253.c | 101 ++++++++++++++++++++++++++++++++++++++++----
2 files changed, 98 insertions(+), 8 deletions(-)

Index: linux-2.6-tip/drivers/clocksource/Kconfig
===================================================================
--- linux-2.6-tip.orig/drivers/clocksource/Kconfig
+++ linux-2.6-tip/drivers/clocksource/Kconfig
@@ -1,11 +1,14 @@
config CLKSRC_I8253
bool

+config CLKEVT_I8253
+ bool
+
config I8253_LOCK
bool

config CLKBLD_I8253
- def_bool y if CLKSRC_I8253 || I8253_LOCK
+ def_bool y if CLKSRC_I8253 || CLKEVT_I8253 || I8253_LOCK

config CLKSRC_MMIO
bool
Index: linux-2.6-tip/drivers/clocksource/i8253.c
===================================================================
--- linux-2.6-tip.orig/drivers/clocksource/i8253.c
+++ linux-2.6-tip/drivers/clocksource/i8253.c
@@ -1,13 +1,14 @@
/*
* i8253 PIT clocksource
*/
-#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/timex.h>
#include <linux/module.h>
#include <linux/i8253.h>
+#include <linux/smp.h>

/*
* Protects access to I/O ports
@@ -49,15 +50,15 @@ static cycle_t i8253_read(struct clockso
* count), it cannot be newer.
*/
jifs = jiffies;
- outb_pit(0x00, PIT_MODE); /* latch the count ASAP */
- count = inb_pit(PIT_CH0); /* read the latched count */
- count |= inb_pit(PIT_CH0) << 8;
+ outb_p(0x00, PIT_MODE); /* latch the count ASAP */
+ count = inb_p(PIT_CH0); /* read the latched count */
+ count |= inb_p(PIT_CH0) << 8;

/* VIA686a test code... reset the latch if count > max + 1 */
if (count > LATCH) {
- outb_pit(0x34, PIT_MODE);
- outb_pit(PIT_LATCH & 0xff, PIT_CH0);
- outb_pit(PIT_LATCH >> 8, PIT_CH0);
+ outb_p(0x34, PIT_MODE);
+ outb_p(PIT_LATCH & 0xff, PIT_CH0);
+ outb_p(PIT_LATCH >> 8, PIT_CH0);
count = PIT_LATCH - 1;
}

@@ -99,3 +100,89 @@ int __init clocksource_i8253_init(void)
return clocksource_register_hz(&i8253_cs, PIT_TICK_RATE);
}
#endif
+
+#ifdef CONFIG_CLKEVT_I8253
+/*
+ * Initialize the PIT timer.
+ *
+ * This is also called after resume to bring the PIT into operation again.
+ */
+static void init_pit_timer(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ raw_spin_lock(&i8253_lock);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(0x34, PIT_MODE);
+ outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
+ outb_p(LATCH >> 8 , PIT_CH0); /* MSB */
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+ evt->mode == CLOCK_EVT_MODE_ONESHOT) {
+ outb_p(0x30, PIT_MODE);
+ outb_p(0, PIT_CH0);
+ outb_p(0, PIT_CH0);
+ }
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* One shot setup */
+ outb_p(0x38, PIT_MODE);
+ break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ /* Nothing to do here */
+ break;
+ }
+ raw_spin_unlock(&i8253_lock);
+}
+
+/*
+ * Program the next event in oneshot mode
+ *
+ * Delta is given in PIT ticks
+ */
+static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+ raw_spin_lock(&i8253_lock);
+ outb_p(delta & 0xff , PIT_CH0); /* LSB */
+ outb_p(delta >> 8 , PIT_CH0); /* MSB */
+ raw_spin_unlock(&i8253_lock);
+
+ return 0;
+}
+
+/*
+ * On UP the PIT can serve all of the possible timer functions. On SMP systems
+ * it can be solely used for the global tick.
+ */
+struct clock_event_device i8253_clockevent = {
+ .name = "pit",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .set_mode = init_pit_timer,
+ .set_next_event = pit_next_event,
+};
+
+/*
+ * Initialize the conversion factor and the min/max deltas of the clock event
+ * structure and register the clock event source with the framework.
+ */
+void __init clockevent_i8253_init(bool oneshot)
+{
+ if (oneshot)
+ i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT;
+ /*
+ * Start pit with the boot cpu mask. x86 might make it global
+ * when it is used as broadcast device later.
+ */
+ i8253_clockevent.cpumask = cpumask_of(smp_processor_id());
+
+ clockevents_config_and_register(&i8253_clockevent, PIT_TICK_RATE,
+ 0xF, 0x7FFF);
+}
+#endif


2011-06-24 14:31:07

by Thomas Gleixner

[permalink] [raw]
Subject: [tip:timers/cleanup] i8253: Create common clockevent implementation

Commit-ID: 9f9119424bbc4e1c4c8690ea418fa6129dc9fa04
Gitweb: http://git.kernel.org/tip/9f9119424bbc4e1c4c8690ea418fa6129dc9fa04
Author: Thomas Gleixner <[email protected]>
AuthorDate: Thu, 9 Jun 2011 13:08:25 +0000
Committer: Thomas Gleixner <[email protected]>
CommitDate: Fri, 24 Jun 2011 16:22:54 +0200

i8253: Create common clockevent implementation

arm, mips and x86 implement i8253 based clockevents. All the same code
copied. Create a common implementation in drivers/clocksource/i8253.c.

About time to rename drivers/clocksource/ to something else.

Signed-off-by: Thomas Gleixner <[email protected]>
Cc: Russell King <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: John Stultz <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]

---
drivers/clocksource/Kconfig | 5 ++-
drivers/clocksource/i8253.c | 101 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 98 insertions(+), 8 deletions(-)

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 330343b..d8d3e02 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -1,11 +1,14 @@
config CLKSRC_I8253
bool

+config CLKEVT_I8253
+ bool
+
config I8253_LOCK
bool

config CLKBLD_I8253
- def_bool y if CLKSRC_I8253 || I8253_LOCK
+ def_bool y if CLKSRC_I8253 || CLKEVT_I8253 || I8253_LOCK

config CLKSRC_MMIO
bool
diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c
index e594f52..27c49e6 100644
--- a/drivers/clocksource/i8253.c
+++ b/drivers/clocksource/i8253.c
@@ -1,13 +1,14 @@
/*
* i8253 PIT clocksource
*/
-#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/timex.h>
#include <linux/module.h>
#include <linux/i8253.h>
+#include <linux/smp.h>

/*
* Protects access to I/O ports
@@ -47,15 +48,15 @@ static cycle_t i8253_read(struct clocksource *cs)
* count), it cannot be newer.
*/
jifs = jiffies;
- outb_pit(0x00, PIT_MODE); /* latch the count ASAP */
- count = inb_pit(PIT_CH0); /* read the latched count */
- count |= inb_pit(PIT_CH0) << 8;
+ outb_p(0x00, PIT_MODE); /* latch the count ASAP */
+ count = inb_p(PIT_CH0); /* read the latched count */
+ count |= inb_p(PIT_CH0) << 8;

/* VIA686a test code... reset the latch if count > max + 1 */
if (count > LATCH) {
- outb_pit(0x34, PIT_MODE);
- outb_pit(PIT_LATCH & 0xff, PIT_CH0);
- outb_pit(PIT_LATCH >> 8, PIT_CH0);
+ outb_p(0x34, PIT_MODE);
+ outb_p(PIT_LATCH & 0xff, PIT_CH0);
+ outb_p(PIT_LATCH >> 8, PIT_CH0);
count = PIT_LATCH - 1;
}

@@ -97,3 +98,89 @@ int __init clocksource_i8253_init(void)
return clocksource_register_hz(&i8253_cs, PIT_TICK_RATE);
}
#endif
+
+#ifdef CONFIG_CLKEVT_I8253
+/*
+ * Initialize the PIT timer.
+ *
+ * This is also called after resume to bring the PIT into operation again.
+ */
+static void init_pit_timer(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ raw_spin_lock(&i8253_lock);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(0x34, PIT_MODE);
+ outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
+ outb_p(LATCH >> 8 , PIT_CH0); /* MSB */
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+ evt->mode == CLOCK_EVT_MODE_ONESHOT) {
+ outb_p(0x30, PIT_MODE);
+ outb_p(0, PIT_CH0);
+ outb_p(0, PIT_CH0);
+ }
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* One shot setup */
+ outb_p(0x38, PIT_MODE);
+ break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ /* Nothing to do here */
+ break;
+ }
+ raw_spin_unlock(&i8253_lock);
+}
+
+/*
+ * Program the next event in oneshot mode
+ *
+ * Delta is given in PIT ticks
+ */
+static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+ raw_spin_lock(&i8253_lock);
+ outb_p(delta & 0xff , PIT_CH0); /* LSB */
+ outb_p(delta >> 8 , PIT_CH0); /* MSB */
+ raw_spin_unlock(&i8253_lock);
+
+ return 0;
+}
+
+/*
+ * On UP the PIT can serve all of the possible timer functions. On SMP systems
+ * it can be solely used for the global tick.
+ */
+struct clock_event_device i8253_clockevent = {
+ .name = "pit",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .set_mode = init_pit_timer,
+ .set_next_event = pit_next_event,
+};
+
+/*
+ * Initialize the conversion factor and the min/max deltas of the clock event
+ * structure and register the clock event source with the framework.
+ */
+void __init clockevent_i8253_init(bool oneshot)
+{
+ if (oneshot)
+ i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT;
+ /*
+ * Start pit with the boot cpu mask. x86 might make it global
+ * when it is used as broadcast device later.
+ */
+ i8253_clockevent.cpumask = cpumask_of(smp_processor_id());
+
+ clockevents_config_and_register(&i8253_clockevent, PIT_TICK_RATE,
+ 0xF, 0x7FFF);
+}
+#endif

2011-06-25 20:03:08

by Stijn Devriendt

[permalink] [raw]
Subject: Re: [patch 1/5] i8253: Create common clockevent implementation

> +/*
> + * Initialize the conversion factor and the min/max deltas of the clock event
> + * structure and register the clock event source with the framework.
> + */
> +void __init clockevent_i8253_init(bool oneshot)
> +{
> + ? ? ? if (oneshot)
> + ? ? ? ? ? ? ? i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT;
> + ? ? ? /*
> + ? ? ? ?* Start pit with the boot cpu mask. x86 might make it global
> + ? ? ? ?* when it is used as broadcast device later.
> + ? ? ? ?*/
> + ? ? ? i8253_clockevent.cpumask = cpumask_of(smp_processor_id());
> +
> + ? ? ? clockevents_config_and_register(&i8253_clockevent, PIT_TICK_RATE,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xF, 0x7FFF);
> +}
> +#endif
>
Both this function and the i8253_clockevent declaration seem to be missing
from include/linux/i8253.h causing compile failures for at least x86.

I was just trying to compile tip of
git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched-devel.git

Should be fixed by applying the following patch.

commit 0c24072a8d580acd5b4fc57009b72b217c0f23d9
Author: Stijn Devriendt <[email protected]>
Date: Sat Jun 25 22:04:53 2011 +0200

Fix missing declarations of i8253.

Signed-off-by: Stijn Devriendt <[email protected]>

diff --git a/include/linux/i8253.h b/include/linux/i8253.h
index 0770fc5..e6c032f 100644
--- a/include/linux/i8253.h
+++ b/include/linux/i8253.h
@@ -22,6 +22,10 @@

extern raw_spinlock_t i8253_lock;

+extern struct clock_event_device i8253_clockevent;
+
extern void setup_pit_timer(void);

+extern void clockevent_i8253_init(bool oneshot);
+
#endif /* __LINUX_I8253_H */

Subject: Re: [patch 1/5] i8253: Create common clockevent implementation

(2011/06/26 5:03), Stijn Devriendt wrote:
>> +/*
>> + * Initialize the conversion factor and the min/max deltas of the clock event
>> + * structure and register the clock event source with the framework.
>> + */
>> +void __init clockevent_i8253_init(bool oneshot)
>> +{
>> + if (oneshot)
>> + i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT;
>> + /*
>> + * Start pit with the boot cpu mask. x86 might make it global
>> + * when it is used as broadcast device later.
>> + */
>> + i8253_clockevent.cpumask = cpumask_of(smp_processor_id());
>> +
>> + clockevents_config_and_register(&i8253_clockevent, PIT_TICK_RATE,
>> + 0xF, 0x7FFF);
>> +}
>> +#endif
>>
> Both this function and the i8253_clockevent declaration seem to be missing
> from include/linux/i8253.h causing compile failures for at least x86.
>
> I was just trying to compile tip of
> git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched-devel.git

I've met same problem on latest tip tree.

> Should be fixed by applying the following patch.

We still need to expose clocksource_i8253_init() too
for CONFIG_X86_64=n.
So, could you update your patch (and send it as a patch mail)?

Thank you,

>
> commit 0c24072a8d580acd5b4fc57009b72b217c0f23d9
> Author: Stijn Devriendt <[email protected]>
> Date: Sat Jun 25 22:04:53 2011 +0200
>
> Fix missing declarations of i8253.
>
> Signed-off-by: Stijn Devriendt <[email protected]>
>
> diff --git a/include/linux/i8253.h b/include/linux/i8253.h
> index 0770fc5..e6c032f 100644
> --- a/include/linux/i8253.h
> +++ b/include/linux/i8253.h
> @@ -22,6 +22,10 @@
>
> extern raw_spinlock_t i8253_lock;
>
> +extern struct clock_event_device i8253_clockevent;
> +
> extern void setup_pit_timer(void);
>
> +extern void clockevent_i8253_init(bool oneshot);
> +
> #endif /* __LINUX_I8253_H */


--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: [email protected]