linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHSET][2.6-test4][0/6]Support for HPET based timer - Take 2
@ 2003-08-28 23:41 Pallipadi, Venkatesh
  2003-08-29 18:23 ` Andrew Morton
  0 siblings, 1 reply; 15+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-28 23:41 UTC (permalink / raw)
  To: torvalds, akpm; +Cc: linux-kernel, Nakajima, Jun



Resending the patch. A major change from previous version is
elimination of fixmap for HPET. Based on Andrew Morton's suggestion, 
we have a new hook in init/main.c for late_time_init(), at which 
time we can use ioremap, in place of fixmap.
Impact on other archs: Calibrate_delay() (and hence loops_per_jiffy
calculation) has moved down in main.c, from after time_init() 
to after kmem_cache_init().


Patchset description:
1/6 - hpet1.patch - main.c change to introduce late_time_init()
2/6 - hpet2.patch - acpi boot time parsing changes to look for HPET
3/6 - hpet3.patch - Miscallaneous makefile and config changes
4/6 - hpet4.patch - All the changes required to use HPET in place
                    of PIT as the kernel base-timer at IRQ 0.
5/6 - hpet5.patch - All changes required to support timer services
                    (gettimeofday) with HPET. There are two options:
                    - Use HPET for gettimeofday.
                    - Use rdtsc for gettimeofday.
                    rdtsc is still faster then HPET reads, but HPET
                    has advantage that its rate remain same,
                    irrespective of CPU frequency. Also, HPET is
                    more scalable than TSC in case of multi-node
                    systems. So, our timer priority is
                    platform_specific_timer(if any), timer_hpet
                    and timer_tsc in that order.
6/6 - hpet6.patch - This can be a standalone patch. Without this
                    patch we loose interrupt generation capability
                    of RTC (/dev/rtc), due to HPET. With this patch
                    we basically try to emulate RTC interrupt
                    functions in software using HPET counter 1.
                    This is only required to provide compatibility
                    to the applications that depend on rtc driver's
                    interrupt generation capability.
                    This emulation will not be as accurate as RTC
                    interrupt, as HPET is not tied to RTC hardware
                    and does not know anything about RTC time.
                    But should enough for compatibility purposes.

All comments/feedbacks welcome.

Thanks,
-Venkatesh


HPET Description
High Precision Event Timer (HPET) is next generation timer
hardware and has various advantages over legacy 8254
(PIT) timer, like:
- Associated registers are mapped to memory space. So, we no
  longer require in and out on legacy ioports
- Memory map address is reported by ACPI (and are not
  hard-coded)
- Each timer can be configured to generate separate interrupts,
  even sharing lines with PCI devices
- HPET has a minimum period of 100 nanosecs and is not fixed.
  Giving a flexibility of increasing the resolution in future.
- Most current implementations has 3 counters, but in future,
  we can have as many as 32 timers per block, and 8
  HPET timer blocks (total 256 timers)
- Can support 32bit and 64bit counting

(Refer to http://www.intel.com/labs/platcomp/hpet/hpetspec.htm
 for complete specs)

The patchset that follow adds support for High Precision Event
Timer (HPET) based timer in kernel. This uses the HPET in
LegacyReplacement mode (so that counter 0 will be tied to IRQ0,
and counter 1 will be tied to IRQ 8). In this mode, HPET overrides
PIT and RTC interrupt lines. The patch will enable HPET by default,
on systems where ACPI tables reports this feature. The patch will
have no impact on systems that do not support this feature.



^ permalink raw reply	[flat|nested] 15+ messages in thread
[parent not found: <pEGJ.73p.5@gated-at.bofh.it>]
* RE: [PATCHSET][2.6-test4][0/6]Support for HPET based timer - Take 2
@ 2003-08-29 16:12 Pallipadi, Venkatesh
  2003-08-30  4:59 ` David Mosberger-Tang
  0 siblings, 1 reply; 15+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-29 16:12 UTC (permalink / raw)
  To: David Mosberger-Tang; +Cc: linux-kernel



The part of the patch that does the HPET initialization for timer
interrupt, and general HPET registers read/write/programming can be
common across architectures.
However, different archs diverge, when it comes to gettimeofday-timer
implementation (tsc, pit, itc, hpet, ) and we may still have to keep
that part architecture specific. 

Thanks,
Venkatesh

> -----Original Message-----
> From: David Mosberger-Tang [mailto:David.Mosberger@acm.org] 
> Sent: Thursday, August 28, 2003 8:41 PM
> To: Pallipadi, Venkatesh
> Cc: linux-kernel@vger.kernel.org
> Subject: Re: [PATCHSET][2.6-test4][0/6]Support for HPET based 
> timer - Take 2
> 
> 
> >>>>> On Fri, 29 Aug 2003 01:50:09 +0200, "Pallipadi, 
> Venkatesh" <venkatesh.pallipadi@intel.com> said:
> 
>   Venkatesh> Resending the patch. A major change from previous version
>   Venkatesh> is elimination of fixmap for HPET. Based on Andrew
>   Venkatesh> Morton's suggestion, we have a new hook in init/main.c
>   Venkatesh> for late_time_init(), at which time we can use ioremap,
>   Venkatesh> in place of fixmap.  Impact on other archs:
>   Venkatesh> Calibrate_delay() (and hence loops_per_jiffy calculation)
>   Venkatesh> has moved down in main.c, from after time_init() to after
>   Venkatesh> kmem_cache_init().
> 
>   Venkatesh> All comments/feedbacks welcome.
> 
> How much is really architecture-specific?  HPET isn't x86-only so
> sooner or later, we'll have to move it out of arch/i386 anyhow.
> 
> 	--david
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread
* RE: [PATCHSET][2.6-test4][0/6]Support for HPET based timer - Take 2
@ 2003-08-29 23:58 Pallipadi, Venkatesh
  2003-09-05 22:26 ` George Anzinger
  0 siblings, 1 reply; 15+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-29 23:58 UTC (permalink / raw)
  To: Andrew Morton; +Cc: torvalds, linux-kernel, Nakajima, Jun

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




> -----Original Message-----
> From: Andrew Morton [mailto:akpm@osdl.org] 
> 
> We seem to keep on proliferating home-grown x86 64-bit math functions.
> 
> Do you really need these?  Is it possible to use do_div() and 
> the C 64x64
> `*' operator instead?
> 


We can change these handcoded 64 bit divs to do_div, with just an
additional data copy 
(as do_div changes dividend in place). But, changing mul into 64x64 '*'
may be tricky. 
Gcc seem to generate a combination of mul, 2imul and add, where as we
are happy with 
using only one mull here.

> 
> I'd like the rtc emulation patch to be redone to remove the 
> ifdefs please,
> they're a real eyesore.
> 
> At the top of rtc.c, do something like this:
> 
> #ifndef CONFIG_HPET_EMULATE_RTC
> #define is_hpet_enabled() 0
> #define hpet_set_alarm_time(hrs, min, sec) 0
> #define hpet_set_periodic_freq(arg) 0
> static inline int hpet_mask_rtc_irq_bit(int arg) { return 0; }
> #define hpet_rtc_timer_init() do { } while (0)
> #define hpet_rtc_dropped_irq() 0
> #endif
> 
> And then all those eleven ifdefs can be removed from rtc.c.


Yes. That surely makes the patch lot more cleaner. Attached is the
updated rtc 
emulation patch.

Thanks,
-Venkatesh

[-- Attachment #2: hpet06_new.patch --]
[-- Type: application/octet-stream, Size: 14753 bytes --]

diff -purN linux-2.6.0-test4-hpetnortc/arch/i386/kernel/time_hpet.c linux-2.6.0-test4-hpet/arch/i386/kernel/time_hpet.c
--- linux-2.6.0-test4-hpetnortc/arch/i386/kernel/time_hpet.c	2003-08-29 17:56:48.000000000 -0700
+++ linux-2.6.0-test4-hpet/arch/i386/kernel/time_hpet.c	2003-08-28 16:20:50.000000000 -0700
@@ -168,4 +168,225 @@ static int __init hpet_setup(char* str)
 
 __setup("hpet=", hpet_setup);
 
+#ifdef CONFIG_HPET_EMULATE_RTC
+/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET 
+ * is enabled, we support RTC interrupt functionality in software. 
+ * RTC has 3 kinds of interrupts:
+ * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
+ *    is updated
+ * 2) Alarm Interrupt - generate an interrupt at a specific time of day
+ * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
+ *    2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
+ * (1) and (2) above are implemented using polling at a frequency of 
+ * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
+ * overhead. (DEFAULT_RTC_INT_FREQ)
+ * For (3), we use interrupts at 64Hz or user specified periodic 
+ * frequency, whichever is higher.
+ */
+#include <linux/mc146818rtc.h>
+#include <linux/rtc.h>
+
+extern irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern void get_rtc_time(struct rtc_time *rtc_tm);
+
+#define DEFAULT_RTC_INT_FREQ 	64
+#define RTC_NUM_INTS 		1
+
+static unsigned long UIE_on;
+static unsigned long prev_update_sec;
+
+static unsigned long AIE_on;
+static struct rtc_time alarm_time;
+
+static unsigned long PIE_on;
+static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ;
+static unsigned long PIE_count;
+
+static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */
+
+/*
+ * Timer 1 for RTC, we do not use periodic interrupt feature, 
+ * even if HPET supports periodic interrupts on Timer 1.
+ * The reason being, to set up a periodic interrupt in HPET, we need to 
+ * stop the main counter. And if we do that everytime someone diables/enables
+ * RTC, we will have adverse effect on main kernel timer running on Timer 0.
+ * So, for the time being, simulate the periodic interrupt in software.
+ * 
+ * hpet_rtc_timer_init() is called for the first time and during subsequent 
+ * interuppts reinit happens through hpet_rtc_timer_reinit().
+ */
+int hpet_rtc_timer_init(void)
+{
+	unsigned int cfg, cnt;
+	unsigned long flags;
+
+	if (!is_hpet_enabled())
+		return 0;
+	/*
+	 * Set the counter 1 and enable the interrupts.
+	 */
+	if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
+		hpet_rtc_int_freq = PIE_freq;
+	else
+		hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+	local_irq_save(flags);
+	cnt = hpet_readl(HPET_COUNTER);
+	cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
+	hpet_writel(cnt, HPET_T1_CMP);
+	local_irq_restore(flags);
+
+	cfg = hpet_readl(HPET_T1_CFG);
+	cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT;
+	hpet_writel(cfg, HPET_T1_CFG);
+
+	return 1;
+}
+
+static void hpet_rtc_timer_reinit(void)
+{
+	unsigned int cfg, cnt;
+
+	if (!(PIE_on | AIE_on | UIE_on))
+		return;
+
+	if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
+		hpet_rtc_int_freq = PIE_freq;
+	else
+		hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+	/* It is more accurate to use the comparator value than current count.*/
+	cnt = hpet_readl(HPET_T1_CMP);
+	cnt += hpet_tick*HZ/hpet_rtc_int_freq;
+	hpet_writel(cnt, HPET_T1_CMP);
+
+	cfg = hpet_readl(HPET_T1_CFG);
+	cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT;
+	hpet_writel(cfg, HPET_T1_CFG);
+
+	return;
+}
+
+/* 
+ * The functions below are called from rtc driver. 
+ * Return 0 if HPET is not being used.
+ * Otherwise do the necessary changes and return 1.
+ */
+int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
+{
+	if (!is_hpet_enabled())
+		return 0;
+
+	if (bit_mask & RTC_UIE)
+		UIE_on = 0;
+	if (bit_mask & RTC_PIE)
+		PIE_on = 0;
+	if (bit_mask & RTC_AIE)
+		AIE_on = 0;
+
+	return 1;
+}
+
+int hpet_set_rtc_irq_bit(unsigned long bit_mask)
+{
+	int timer_init_reqd = 0;
+
+	if (!is_hpet_enabled())
+		return 0;
+
+	if (!(PIE_on | AIE_on | UIE_on))
+		timer_init_reqd = 1;
+
+	if (bit_mask & RTC_UIE) {
+		UIE_on = 1;
+	}
+	if (bit_mask & RTC_PIE) {
+		PIE_on = 1;
+		PIE_count = 0;
+	}
+	if (bit_mask & RTC_AIE) {
+		AIE_on = 1;
+	}
+
+	if (timer_init_reqd)
+		hpet_rtc_timer_init();
+
+	return 1;
+}
+
+int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec)
+{
+	if (!is_hpet_enabled())
+		return 0;
+
+	alarm_time.tm_hour = hrs;
+	alarm_time.tm_min = min;
+	alarm_time.tm_sec = sec;
+
+	return 1;
+}
+
+int hpet_set_periodic_freq(unsigned long freq)
+{
+	if (!is_hpet_enabled())
+		return 0;
+
+	PIE_freq = freq;
+	PIE_count = 0;
+
+	return 1;
+}
+
+int hpet_rtc_dropped_irq(void)
+{
+	if (!is_hpet_enabled())
+		return 0;
+
+	return 1;
+}
+
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct rtc_time curr_time;
+	unsigned long rtc_int_flag = 0;
+	int call_rtc_interrupt = 0;
+
+	hpet_rtc_timer_reinit();
+
+	if (UIE_on | AIE_on) {
+		get_rtc_time(&curr_time);
+	}
+	if (UIE_on) {
+		if (curr_time.tm_sec != prev_update_sec) {
+			/* Set update int info, call real rtc int routine */
+			call_rtc_interrupt = 1;
+			rtc_int_flag = RTC_UF;
+			prev_update_sec = curr_time.tm_sec;
+		}
+	}
+	if (PIE_on) {
+		PIE_count++;
+		if (PIE_count >= hpet_rtc_int_freq/PIE_freq) {
+			/* Set periodic int info, call real rtc int routine */
+			call_rtc_interrupt = 1;
+			rtc_int_flag |= RTC_PF;
+			PIE_count = 0;
+		}
+	}
+	if (AIE_on) {
+		if ((curr_time.tm_sec == alarm_time.tm_sec) &&
+		    (curr_time.tm_min == alarm_time.tm_min) &&
+		    (curr_time.tm_hour == alarm_time.tm_hour)) {
+			/* Set alarm int info, call real rtc int routine */
+			call_rtc_interrupt = 1;
+			rtc_int_flag |= RTC_AF;
+		}
+	}
+	if (call_rtc_interrupt) {
+		rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
+		rtc_interrupt(rtc_int_flag, dev_id, regs);
+	}
+	return IRQ_HANDLED;
+}
+#endif
 
diff -purN linux-2.6.0-test4-hpetnortc/drivers/char/rtc.c linux-2.6.0-test4-hpet/drivers/char/rtc.c
--- linux-2.6.0-test4-hpetnortc/drivers/char/rtc.c	2003-08-29 17:56:48.000000000 -0700
+++ linux-2.6.0-test4-hpet/drivers/char/rtc.c	2003-08-29 17:06:24.000000000 -0700
@@ -44,10 +44,12 @@
  *      1.11    Takashi Iwai: Kernel access functions
  *			      rtc_register/rtc_unregister/rtc_control
  *      1.11a   Daniele Bellucci: Audit create_proc_read_entry in rtc_init
+ *	1.12	Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
+ *		CONFIG_HPET_EMULATE_RTC
  *
  */
 
-#define RTC_VERSION		"1.11a"
+#define RTC_VERSION		"1.12"
 
 #define RTC_IO_EXTENT	0x8
 
@@ -80,6 +82,10 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+#if defined(__i386__)
+#include <asm/hpet.h>
+#endif
+
 #ifdef __sparc__
 #include <linux/pci.h>
 #include <asm/ebus.h>
@@ -95,6 +101,17 @@ static int rtc_irq = PCI_IRQ_NONE;
 static int rtc_has_irq = 1;
 #endif
 
+#ifndef CONFIG_HPET_EMULATE_RTC
+#define is_hpet_enabled()			0
+#define hpet_set_alarm_time(hrs, min, sec) 	0
+#define hpet_set_periodic_freq(arg) 		0
+#define hpet_mask_rtc_irq_bit(arg) 		0
+#define hpet_set_rtc_irq_bit(arg) 		0
+#define hpet_rtc_timer_init() 			do { } while (0)
+#define hpet_rtc_dropped_irq() 			0
+static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {return 0;}
+#endif
+
 /*
  *	We sponge a minor off of the misc major. No need slurping
  *	up another valuable major dev number for this. If you add
@@ -120,7 +137,7 @@ static int rtc_ioctl(struct inode *inode
 static unsigned int rtc_poll(struct file *file, poll_table *wait);
 #endif
 
-static void get_rtc_time (struct rtc_time *rtc_tm);
+void get_rtc_time (struct rtc_time *rtc_tm);
 static void get_rtc_alm_time (struct rtc_time *alm_tm);
 #if RTC_IRQ
 static void rtc_dropped_irq(unsigned long data);
@@ -182,7 +199,7 @@ static const unsigned char days_in_mo[] 
  *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
  */
 
-static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	/*
 	 *	Can be an alarm interrupt, update complete interrupt,
@@ -194,7 +211,16 @@ static irqreturn_t rtc_interrupt(int irq
 	spin_lock (&rtc_lock);
 	rtc_irq_data += 0x100;
 	rtc_irq_data &= ~0xff;
-	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+	if (is_hpet_enabled()) {
+		/*
+		 * In this case it is HPET RTC interrupt handler
+		 * calling us, with the interrupt information
+		 * passed as arg1, instead of irq.
+		 */
+		rtc_irq_data |= (unsigned long)irq & 0xF0;
+	} else {
+		rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+	}
 
 	if (rtc_status & RTC_TIMER_ON)
 		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
@@ -429,6 +455,12 @@ static int rtc_do_ioctl(unsigned int cmd
 		sec = alm_tm.tm_sec;
 
 		spin_lock_irq(&rtc_lock);
+		if (hpet_set_alarm_time(hrs, min, sec)) {
+			/*
+			 * Fallthru and set alarm time in CMOS too, 
+			 * so that we will get proper value in RTC_ALM_READ
+			 */
+		}
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
 		    RTC_ALWAYS_BCD)
 		{
@@ -582,6 +614,10 @@ static int rtc_do_ioctl(unsigned int cmd
 			return -EINVAL;
 
 		spin_lock_irq(&rtc_lock);
+		if (hpet_set_periodic_freq(arg)) {
+			spin_unlock_irq(&rtc_lock);
+			return 0;
+		}
 		rtc_freq = arg;
 
 		val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
@@ -667,13 +703,14 @@ static int rtc_release(struct inode *ino
 	 */
 
 	spin_lock_irq(&rtc_lock);
-	tmp = CMOS_READ(RTC_CONTROL);
-	tmp &=  ~RTC_PIE;
-	tmp &=  ~RTC_AIE;
-	tmp &=  ~RTC_UIE;
-	CMOS_WRITE(tmp, RTC_CONTROL);
-	CMOS_READ(RTC_INTR_FLAGS);
-
+	if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
+		tmp = CMOS_READ(RTC_CONTROL);
+		tmp &=  ~RTC_PIE;
+		tmp &=  ~RTC_AIE;
+		tmp &=  ~RTC_UIE;
+		CMOS_WRITE(tmp, RTC_CONTROL);
+		CMOS_READ(RTC_INTR_FLAGS);
+	}
 	if (rtc_status & RTC_TIMER_ON) {
 		rtc_status &= ~RTC_TIMER_ON;
 		del_timer(&rtc_irq_timer);
@@ -765,12 +802,14 @@ int rtc_unregister(rtc_task_t *task)
 	rtc_callback = NULL;
 	
 	/* disable controls */
-	tmp = CMOS_READ(RTC_CONTROL);
-	tmp &= ~RTC_PIE;
-	tmp &= ~RTC_AIE;
-	tmp &= ~RTC_UIE;
-	CMOS_WRITE(tmp, RTC_CONTROL);
-	CMOS_READ(RTC_INTR_FLAGS);
+	if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
+		tmp = CMOS_READ(RTC_CONTROL);
+		tmp &= ~RTC_PIE;
+		tmp &= ~RTC_AIE;
+		tmp &= ~RTC_UIE;
+		CMOS_WRITE(tmp, RTC_CONTROL);
+		CMOS_READ(RTC_INTR_FLAGS);
+	}
 	if (rtc_status & RTC_TIMER_ON) {
 		rtc_status &= ~RTC_TIMER_ON;
 		del_timer(&rtc_irq_timer);
@@ -822,6 +861,10 @@ static struct miscdevice rtc_dev=
 	&rtc_fops
 };
 
+#if RTC_IRQ
+static irqreturn_t (*rtc_int_handler_ptr)(int irq, void *dev_id, struct pt_regs *regs);
+#endif
+
 static int __init rtc_init(void)
 {
 #if defined(__alpha__) || defined(__mips__)
@@ -889,12 +932,20 @@ no_irq:
 	}
 
 #if RTC_IRQ
-	if (request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL)) {
+	if (is_hpet_enabled()) {
+		rtc_int_handler_ptr = hpet_rtc_interrupt;
+	} else {
+		rtc_int_handler_ptr = rtc_interrupt;
+	}
+
+	if(request_irq(RTC_IRQ, rtc_int_handler_ptr, SA_INTERRUPT, "rtc", NULL)) {
 		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
 		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
 		release_region(RTC_PORT(0), RTC_IO_EXTENT);
 		return -EIO;
 	}
+	hpet_rtc_timer_init();
+
 #endif
 
 #endif /* __sparc__ vs. others */
@@ -965,10 +1016,12 @@ no_irq:
 	init_timer(&rtc_irq_timer);
 	rtc_irq_timer.function = rtc_dropped_irq;
 	spin_lock_irq(&rtc_lock);
-	/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
-	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
-	spin_unlock_irq(&rtc_lock);
 	rtc_freq = 1024;
+	if (!hpet_set_periodic_freq(rtc_freq)) {
+		/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
+		CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
+	}
+	spin_unlock_irq(&rtc_lock);
 no_irq2:
 #endif
 
@@ -1019,6 +1072,11 @@ static void rtc_dropped_irq(unsigned lon
 
 	spin_lock_irq (&rtc_lock);
 
+	if (hpet_rtc_dropped_irq()) {
+		spin_unlock_irq(&rtc_lock);
+		return;
+	}
+
 	/* Just in case someone disabled the timer from behind our back... */
 	if (rtc_status & RTC_TIMER_ON)
 		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
@@ -1148,7 +1206,7 @@ static inline unsigned char rtc_is_updat
 	return uip;
 }
 
-static void get_rtc_time(struct rtc_time *rtc_tm)
+void get_rtc_time(struct rtc_time *rtc_tm)
 {
 	unsigned long uip_watchdog = jiffies;
 	unsigned char ctrl;
@@ -1254,6 +1312,10 @@ static void mask_rtc_irq_bit(unsigned ch
 	unsigned char val;
 
 	spin_lock_irq(&rtc_lock);
+	if (hpet_mask_rtc_irq_bit(bit)) {
+		spin_unlock_irq(&rtc_lock);
+		return;
+	}
 	val = CMOS_READ(RTC_CONTROL);
 	val &=  ~bit;
 	CMOS_WRITE(val, RTC_CONTROL);
@@ -1268,6 +1330,10 @@ static void set_rtc_irq_bit(unsigned cha
 	unsigned char val;
 
 	spin_lock_irq(&rtc_lock);
+	if (hpet_set_rtc_irq_bit(bit)) {
+		spin_unlock_irq(&rtc_lock);
+		return;
+	}
 	val = CMOS_READ(RTC_CONTROL);
 	val |= bit;
 	CMOS_WRITE(val, RTC_CONTROL);
diff -purN linux-2.6.0-test4-hpetnortc/include/asm-i386/hpet.h linux-2.6.0-test4-hpet/include/asm-i386/hpet.h
--- linux-2.6.0-test4-hpetnortc/include/asm-i386/hpet.h	2003-08-29 17:56:48.000000000 -0700
+++ linux-2.6.0-test4-hpet/include/asm-i386/hpet.h	2003-08-28 16:20:50.000000000 -0700
@@ -102,5 +102,15 @@ extern int is_hpet_capable(void);
 extern int hpet_readl(unsigned long a);
 extern void hpet_writel(unsigned long d, unsigned long a);
 
+#ifdef CONFIG_RTC
+#define CONFIG_HPET_EMULATE_RTC 	1
+extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
+extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
+extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec);
+extern int hpet_set_periodic_freq(unsigned long freq);
+extern int hpet_rtc_dropped_irq(void);
+extern int hpet_rtc_timer_init(void);
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+#endif /* CONFIG_RTC */
 #endif /* CONFIG_HPET_TIMER */
 #endif /* _I386_HPET_H */
diff -purN linux-2.6.0-test4-hpetnortc/include/asm-i386/mc146818rtc.h linux-2.6.0-test4-hpet/include/asm-i386/mc146818rtc.h
--- linux-2.6.0-test4-hpetnortc/include/asm-i386/mc146818rtc.h	2003-08-29 17:56:48.000000000 -0700
+++ linux-2.6.0-test4-hpet/include/asm-i386/mc146818rtc.h	2003-08-28 16:20:50.000000000 -0700
@@ -24,10 +24,6 @@ outb_p((addr),RTC_PORT(0)); \
 outb_p((val),RTC_PORT(1)); \
 })
 
-#ifdef CONFIG_HPET_TIMER
-#define RTC_IRQ 0
-#else
 #define RTC_IRQ 8
-#endif
 
 #endif /* _ASM_MC146818RTC_H */

^ permalink raw reply	[flat|nested] 15+ messages in thread
* RE: [PATCHSET][2.6-test4][0/6]Support for HPET based timer - Take 2
@ 2003-08-30 16:26 Pallipadi, Venkatesh
  0 siblings, 0 replies; 15+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-30 16:26 UTC (permalink / raw)
  To: David.Mosberger; +Cc: linux-kernel


> -----Original Message-----
> From: David Mosberger-Tang [mailto:davidm@mostang.com]
> >>>>> On Fri, 29 Aug 2003 09:12:52 -0700, "Pallipadi, 
> Venkatesh" <venkatesh.pallipadi@intel.com> said:
> 
>   Venkatesh> The part of the patch that does the HPET initialization
>   Venkatesh> for timer interrupt, and general HPET registers
>   Venkatesh> read/write/programming can be common across
>   Venkatesh> architectures.  However, different archs diverge, when it
>   Venkatesh> comes to gettimeofday-timer implementation (tsc, pit,
>   Venkatesh> itc, hpet, ) and we may still have to keep that part
>   Venkatesh> architecture specific.
> 
> Is the time_interpolator interface provided by timex.h sufficient for
> HPET timer-interrupt needs?  I think It ought to be.  If so, perhaps
> all that's missing is that x86 needs to be switched over to that
> interface?
> 

timer_interpolator kind of interface helps for one part of HPET changes.
That is using HPET during gettimeofday(). Unfortunately, i386 has its
own timer infrastructure (which is quite similar to timer_interpolator),
which is already being used by variety of timers that exist (cyclone_timer,
tsc, pit - code under arch/i386/kernel/timers). i386 timers seems to be 
the superset of timer_interpolator.
struct timer_opts{
        int (*init)(char *override);
        void (*mark_offset)(void);
        unsigned long (*get_offset)(void);
        unsigned long long (*monotonic_clock)(void);
        void (*delay)(unsigned long);
};
I agree, in future, it is best to integrate these timers in an 
architecture independent way. 

The other part of HPET change is, change in kernel base timer. In i386, 
along with local APIC timer interrupts, we also have a IRQ0 timer interrupt.
This is where kernel time-keeping happens (similar to TIME_KEEPER_ID in IPF).
This will also used for process times in UP case, when there is no LAPIC.
As of now this interrupt comes from PIT/8254. HPET will replace this too, 
and can be programmed to generate periodic interrupts at a particular rate.
This part may be specific to i386.


Thanks,
-Venkatesh


^ permalink raw reply	[flat|nested] 15+ messages in thread
* RE: [PATCHSET][2.6-test4][0/6]Support for HPET based timer - Take 2
@ 2003-09-06 19:04 Pallipadi, Venkatesh
  2003-09-07 17:57 ` George Anzinger
  0 siblings, 1 reply; 15+ messages in thread
From: Pallipadi, Venkatesh @ 2003-09-06 19:04 UTC (permalink / raw)
  To: George Anzinger; +Cc: Andrew Morton, torvalds, linux-kernel, Nakajima, Jun




> -----Original Message-----
> From: George Anzinger [mailto:george@mvista.com]
> 
> Pallipadi, Venkatesh wrote:
> > 
> > 
> >>-----Original Message-----
> >>From: Andrew Morton [mailto:akpm@osdl.org] 
> >>
> >>We seem to keep on proliferating home-grown x86 64-bit math 
> functions.
> >>
> >>Do you really need these?  Is it possible to use do_div() and 
> >>the C 64x64
> >>`*' operator instead?
> >>
> > 
> > 
> > 
> > We can change these handcoded 64 bit divs to do_div, with just an
> > additional data copy 
> 
> We already have this in .../include/asm-i386/div64.h.  Check usage in 
> .../posix-timers.c to cover archs that have not yet included it in 
> there div64.h.
>


Yes. We can surely use div_long_long_rem from div64 in place of defining 
this again. This kind of code is already there in the existing ia32 timer
code too. I will try and come up with a cleanup patch to replace all 
these individual asm div statements.


> > (as do_div changes dividend in place). But, changing mul 
> into 64x64 '*'
> > may be tricky. 
> > Gcc seem to generate a combination of mul, 2imul and add, 
> where as we
> > are happy with 
> > using only one mull here.
> 
> You just need to do the right casting.  It should like 
> u64=u32*(u64)u32  as in .../kernel/posix-timers.c.  This 
> could also be 
> signed with the same results.  If you really need to do a u64*u32, it 
> will do that as well but takes two mpys.  In this case you will need 
> to do it unsigned to eliminate the third mpy.


Interesting. Is this casting to generate proper mul instruction
some sort of C standard or is it a gcc feature. I just want to
make sure doing this way won't break on some other compiler 
(or on some other version of gcc itself).


Thanks,
-Venkatesh

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

end of thread, other threads:[~2003-09-07 17:57 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-28 23:41 [PATCHSET][2.6-test4][0/6]Support for HPET based timer - Take 2 Pallipadi, Venkatesh
2003-08-29 18:23 ` Andrew Morton
2003-08-29 21:03   ` Erik Andersen
2003-08-31 21:05     ` Linus Torvalds
2003-08-31 22:24       ` Erik Andersen
2003-08-31 22:48         ` Linus Torvalds
2003-09-05 22:19     ` George Anzinger
     [not found] <pEGJ.73p.5@gated-at.bofh.it>
2003-08-29  3:40 ` David Mosberger-Tang
2003-08-29 16:12 Pallipadi, Venkatesh
2003-08-30  4:59 ` David Mosberger-Tang
2003-08-29 23:58 Pallipadi, Venkatesh
2003-09-05 22:26 ` George Anzinger
2003-08-30 16:26 Pallipadi, Venkatesh
2003-09-06 19:04 Pallipadi, Venkatesh
2003-09-07 17:57 ` George Anzinger

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).