public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86: Get irq for hpet timer
@ 2008-05-16  6:05 Kevin Hao
  2008-05-16  7:53 ` Balaji Rao R
  2008-05-16  8:46 ` Clemens Ladisch
  0 siblings, 2 replies; 20+ messages in thread
From: Kevin Hao @ 2008-05-16  6:05 UTC (permalink / raw)
  To: venkatesh.pallipadi, clemens, bob.picco, mingo, tglx; +Cc: linux-kernel

Hi,

x86: get irq for hpet timer
    
HPET timer's IRQ is 0 by default, so we have to select which irq
will be used for these timers. We wait to set the timer's irq until
we really turn on interrupt in order to reduce the chance of
conflicting with some legacy device.
    
Signed-off-by: Kevin Hao <kexin.hao@windriver.com>

---
 drivers/char/hpet.c  |   62 +++++++++++++++++++++++++++++++++++++------------
 include/linux/hpet.h |    3 +-
 2 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index e7fb0bc..67714c2 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -383,6 +383,51 @@ hpet_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	return hpet_ioctl_common(devp, cmd, arg, 0);
 }
 
+static int hpet_timer_get_irq(struct hpet_dev *devp)
+{
+	struct hpet_timer __iomem *timer;
+	struct hpet __iomem *hpet;
+	struct hpets *hpetp;
+	unsigned long cap, irq_flags;
+	int irq;
+
+	timer = devp->hd_timer;
+	hpet = devp->hd_hpet;
+	hpetp = devp->hd_hpets;
+
+	irq = devp->hd_hdwirq;
+
+	sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
+	irq_flags = devp->hd_flags & HPET_SHARED_IRQ
+					? IRQF_SHARED : IRQF_DISABLED;
+	if (irq) {
+		if (request_irq(irq, hpet_interrupt, irq_flags,
+				devp->hd_name, (void *)devp)) {
+			printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
+			irq = 0;
+		}
+		return irq;
+	}
+
+	cap = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK)
+				 >> Tn_INT_ROUTE_CAP_SHIFT;
+
+	for (irq = find_first_bit(&cap, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
+		irq = find_next_bit(&cap, HPET_MAX_IRQ, 1 + irq)) {
+		if (request_irq(irq, hpet_interrupt, irq_flags,
+				devp->hd_name, (void *)devp)) {
+			printk(KERN_WARNING "hpet: IRQ %d is not free\n", irq);
+			continue;
+		}
+		break;
+	}
+
+	if  (irq >= HPET_MAX_IRQ)
+		irq = 0;
+
+	return irq;
+}
+
 static int hpet_ioctl_ieon(struct hpet_dev *devp)
 {
 	struct hpet_timer __iomem *timer;
@@ -412,21 +457,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
 		devp->hd_flags |= HPET_SHARED_IRQ;
 	spin_unlock_irq(&hpet_lock);
 
-	irq = devp->hd_hdwirq;
-
-	if (irq) {
-		unsigned long irq_flags;
-
-		sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
-		irq_flags = devp->hd_flags & HPET_SHARED_IRQ
-						? IRQF_SHARED : IRQF_DISABLED;
-		if (request_irq(irq, hpet_interrupt, irq_flags,
-				devp->hd_name, (void *)devp)) {
-			printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
-			irq = 0;
-		}
-	}
-
+	irq = hpet_timer_get_irq(devp);
 	if (irq == 0) {
 		spin_lock_irq(&hpet_lock);
 		devp->hd_flags ^= HPET_IE;
@@ -438,6 +469,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
 	t = devp->hd_ireqfreq;
 	v = readq(&timer->hpet_config);
 	g = v | Tn_INT_ENB_CNF_MASK;
+	g |= irq << Tn_INT_ROUTE_CNF_SHIFT;
 
 	if (devp->hd_flags & HPET_PERIODIC) {
 		write_counter(t, &timer->hpet_compare);
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 2dc29ce..440ca72 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -37,6 +37,7 @@ struct hpet {
 #define	hpet_compare	_u1._hpet_compare
 
 #define	HPET_MAX_TIMERS	(32)
+#define HPET_MAX_IRQ	(32)
 
 /*
  * HPET general capabilities register
@@ -64,7 +65,7 @@ struct hpet {
  */
 
 #define	Tn_INT_ROUTE_CAP_MASK		(0xffffffff00000000ULL)
-#define	Tn_INI_ROUTE_CAP_SHIFT		(32UL)
+#define	Tn_INT_ROUTE_CAP_SHIFT		(32UL)
 #define	Tn_FSB_INT_DELCAP_MASK		(0x8000UL)
 #define	Tn_FSB_INT_DELCAP_SHIFT		(15)
 #define	Tn_FSB_EN_CNF_MASK		(0x4000UL)


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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-16  6:05 [PATCH] x86: Get irq for hpet timer Kevin Hao
@ 2008-05-16  7:53 ` Balaji Rao R
  2008-05-16  8:03   ` Kevin Hao
  2008-05-16  8:46 ` Clemens Ladisch
  1 sibling, 1 reply; 20+ messages in thread
From: Balaji Rao R @ 2008-05-16  7:53 UTC (permalink / raw)
  To: Kevin Hao
  Cc: venkatesh.pallipadi, clemens, bob.picco, mingo, tglx,
	linux-kernel

On Fri, May 16, 2008 at 11:35 AM, Kevin Hao <kexin.hao@windriver.com> wrote:
>
> Hi,
>
> x86: get irq for hpet timer
>
> HPET timer's IRQ is 0 by default, so we have to select which irq
> will be used for these timers. We wait to set the timer's irq until
> we really turn on interrupt in order to reduce the chance of
> conflicting with some legacy device.
>
Yes, this is alright. But  i've seen some machines where we have a
valid IRQ in 'devp->hd_hdwirq' which you should not ignore. So, first
check if it is zero and only then do a hpet_timer_get_irq.

--
warm regards

Balaji Rao
NITK Surathkal

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-16  7:53 ` Balaji Rao R
@ 2008-05-16  8:03   ` Kevin Hao
  2008-05-16  8:30     ` Balaji Rao
  0 siblings, 1 reply; 20+ messages in thread
From: Kevin Hao @ 2008-05-16  8:03 UTC (permalink / raw)
  To: Balaji Rao R
  Cc: venkatesh.pallipadi, clemens, bob.picco, mingo, tglx,
	linux-kernel

On Fri, 2008-05-16 at 13:23 +0530, Balaji Rao R wrote:
> On Fri, May 16, 2008 at 11:35 AM, Kevin Hao <kexin.hao@windriver.com> wrote:
> >
> > Hi,
> >
> > x86: get irq for hpet timer
> >
> > HPET timer's IRQ is 0 by default, so we have to select which irq
> > will be used for these timers. We wait to set the timer's irq until
> > we really turn on interrupt in order to reduce the chance of
> > conflicting with some legacy device.
> >
> Yes, this is alright. But  i've seen some machines where we have a
> valid IRQ in 'devp->hd_hdwirq' which you should not ignore. So, first
> check if it is zero and only then do a hpet_timer_get_irq.

Yes, I have checked that case in hpet_timer_get_irq function. See the
following code:

+       irq = devp->hd_hdwirq;


+       if (irq) {
+               if (request_irq(irq, hpet_interrupt, irq_flags,
+                               devp->hd_name, (void *)devp)) {
+                       printk(KERN_ERR "hpet: IRQ %d is not free\n",
irq);
+                       irq = 0;
+               }
+               return irq;
+       }

Is that right?

Thanks for your comments.

Best Regards,
Kevin

> 
> --
> warm regards
> 
> Balaji Rao
> NITK Surathkal

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-16  8:03   ` Kevin Hao
@ 2008-05-16  8:30     ` Balaji Rao
  0 siblings, 0 replies; 20+ messages in thread
From: Balaji Rao @ 2008-05-16  8:30 UTC (permalink / raw)
  To: Kevin Hao
  Cc: venkatesh.pallipadi, clemens, bob.picco, mingo, tglx,
	linux-kernel

On Friday 16 May 2008 01:33:25 pm Kevin Hao wrote:
> On Fri, 2008-05-16 at 13:23 +0530, Balaji Rao R wrote:
> > On Fri, May 16, 2008 at 11:35 AM, Kevin Hao <kexin.hao@windriver.com> 
wrote:
> > > Hi,
> > >
> > > x86: get irq for hpet timer
> > >
> > > HPET timer's IRQ is 0 by default, so we have to select which irq
> > > will be used for these timers. We wait to set the timer's irq until
> > > we really turn on interrupt in order to reduce the chance of
> > > conflicting with some legacy device.
> >
> > Yes, this is alright. But  i've seen some machines where we have a
> > valid IRQ in 'devp->hd_hdwirq' which you should not ignore. So, first
> > check if it is zero and only then do a hpet_timer_get_irq.
>
> Yes, I have checked that case in hpet_timer_get_irq function. See the
> following code:
>
> +       irq = devp->hd_hdwirq;
>
>
> +       if (irq) {
> +               if (request_irq(irq, hpet_interrupt, irq_flags,
> +                               devp->hd_name, (void *)devp)) {
> +                       printk(KERN_ERR "hpet: IRQ %d is not free\n",
> irq);
> +                       irq = 0;
> +               }
> +               return irq;
> +       }
>
> Is that right?
>
Yes. You are right. Sorry for not going through the patch fully before making 
noise.

-- 
Warm Regards,

Balaji Rao
Dept. of Mechanical Engineering
NITK

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-16  6:05 [PATCH] x86: Get irq for hpet timer Kevin Hao
  2008-05-16  7:53 ` Balaji Rao R
@ 2008-05-16  8:46 ` Clemens Ladisch
  2008-05-16  9:14   ` Kevin Hao
  1 sibling, 1 reply; 20+ messages in thread
From: Clemens Ladisch @ 2008-05-16  8:46 UTC (permalink / raw)
  To: Kevin Hao; +Cc: venkatesh.pallipadi, bob.picco, mingo, tglx, linux-kernel

Kevin Hao wrote:
> HPET timer's IRQ is 0 by default, so we have to select which irq
> will be used for these timers. We wait to set the timer's irq until
> we really turn on interrupt in order to reduce the chance of
> conflicting with some legacy device.
>
> +	for (irq = find_first_bit(&cap, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
> +		irq = find_next_bit(&cap, HPET_MAX_IRQ, 1 + irq)) {
> +		if (request_irq(irq, hpet_interrupt, irq_flags,
> +				devp->hd_name, (void *)devp)) {
> +			printk(KERN_WARNING "hpet: IRQ %d is not free\n", irq);
> +			continue;

This warning message will be output for every interrupt that is in use
by another device.  I think it would be better to postpone complaining
until after the loop, if no interrupt has been found at all.


Regards,
Clemens

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-16  8:46 ` Clemens Ladisch
@ 2008-05-16  9:14   ` Kevin Hao
  2008-05-19 16:10     ` Clemens Ladisch
  0 siblings, 1 reply; 20+ messages in thread
From: Kevin Hao @ 2008-05-16  9:14 UTC (permalink / raw)
  To: Clemens Ladisch
  Cc: venkatesh.pallipadi, bob.picco, mingo, tglx, linux-kernel,
	Kevin Hao

On Fri, 2008-05-16 at 10:46 +0200, Clemens Ladisch wrote:
> Kevin Hao wrote:
> > HPET timer's IRQ is 0 by default, so we have to select which irq
> > will be used for these timers. We wait to set the timer's irq until
> > we really turn on interrupt in order to reduce the chance of
> > conflicting with some legacy device.
> >
> > +	for (irq = find_first_bit(&cap, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
> > +		irq = find_next_bit(&cap, HPET_MAX_IRQ, 1 + irq)) {
> > +		if (request_irq(irq, hpet_interrupt, irq_flags,
> > +				devp->hd_name, (void *)devp)) {
> > +			printk(KERN_WARNING "hpet: IRQ %d is not free\n", irq);
> > +			continue;
> 
> This warning message will be output for every interrupt that is in use
> by another device.  I think it would be better to postpone complaining
> until after the loop, if no interrupt has been found at all.
> 

Ok, I agree with you.
This is the revised version.

Best Regards,
Kevin
---
 drivers/char/hpet.c  |   63 ++++++++++++++++++++++++++++++++++++++------------
 include/linux/hpet.h |    3 +-
 2 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index e7fb0bc..0fdc627 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -383,6 +383,52 @@ hpet_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	return hpet_ioctl_common(devp, cmd, arg, 0);
 }
 
+static int hpet_timer_get_irq(struct hpet_dev *devp)
+{
+	struct hpet_timer __iomem *timer;
+	struct hpet __iomem *hpet;
+	struct hpets *hpetp;
+	unsigned long cap, irq_flags;
+	int irq;
+
+	timer = devp->hd_timer;
+	hpet = devp->hd_hpet;
+	hpetp = devp->hd_hpets;
+
+	irq = devp->hd_hdwirq;
+
+	sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
+	irq_flags = devp->hd_flags & HPET_SHARED_IRQ
+					? IRQF_SHARED : IRQF_DISABLED;
+	if (irq) {
+		if (request_irq(irq, hpet_interrupt, irq_flags,
+				devp->hd_name, (void *)devp)) {
+			printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
+			irq = 0;
+		}
+		return irq;
+	}
+
+	cap = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK)
+				 >> Tn_INT_ROUTE_CAP_SHIFT;
+
+	for (irq = find_first_bit(&cap, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
+		irq = find_next_bit(&cap, HPET_MAX_IRQ, 1 + irq)) {
+		if (request_irq(irq, hpet_interrupt, irq_flags,
+				devp->hd_name, (void *)devp))
+			continue;
+		break;
+	}
+
+	if  (irq >= HPET_MAX_IRQ) {
+		printk(KERN_WARNING "hpet: No available IRQ for %s timer\n",
+			devp->hd_name);
+		irq = 0;
+	}
+
+	return irq;
+}
+
 static int hpet_ioctl_ieon(struct hpet_dev *devp)
 {
 	struct hpet_timer __iomem *timer;
@@ -412,21 +458,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
 		devp->hd_flags |= HPET_SHARED_IRQ;
 	spin_unlock_irq(&hpet_lock);
 
-	irq = devp->hd_hdwirq;
-
-	if (irq) {
-		unsigned long irq_flags;
-
-		sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
-		irq_flags = devp->hd_flags & HPET_SHARED_IRQ
-						? IRQF_SHARED : IRQF_DISABLED;
-		if (request_irq(irq, hpet_interrupt, irq_flags,
-				devp->hd_name, (void *)devp)) {
-			printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
-			irq = 0;
-		}
-	}
-
+	irq = hpet_timer_get_irq(devp);
 	if (irq == 0) {
 		spin_lock_irq(&hpet_lock);
 		devp->hd_flags ^= HPET_IE;
@@ -438,6 +470,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
 	t = devp->hd_ireqfreq;
 	v = readq(&timer->hpet_config);
 	g = v | Tn_INT_ENB_CNF_MASK;
+	g |= irq << Tn_INT_ROUTE_CNF_SHIFT;
 
 	if (devp->hd_flags & HPET_PERIODIC) {
 		write_counter(t, &timer->hpet_compare);
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 2dc29ce..440ca72 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -37,6 +37,7 @@ struct hpet {
 #define	hpet_compare	_u1._hpet_compare
 
 #define	HPET_MAX_TIMERS	(32)
+#define HPET_MAX_IRQ	(32)
 
 /*
  * HPET general capabilities register
@@ -64,7 +65,7 @@ struct hpet {
  */
 
 #define	Tn_INT_ROUTE_CAP_MASK		(0xffffffff00000000ULL)
-#define	Tn_INI_ROUTE_CAP_SHIFT		(32UL)
+#define	Tn_INT_ROUTE_CAP_SHIFT		(32UL)
 #define	Tn_FSB_INT_DELCAP_MASK		(0x8000UL)
 #define	Tn_FSB_INT_DELCAP_SHIFT		(15)
 #define	Tn_FSB_EN_CNF_MASK		(0x4000UL)

> 
> Regards,
> Clemens

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-16  9:14   ` Kevin Hao
@ 2008-05-19 16:10     ` Clemens Ladisch
  2008-05-19 21:21       ` Maciej W. Rozycki
  2008-05-20  9:03       ` Kevin Hao
  0 siblings, 2 replies; 20+ messages in thread
From: Clemens Ladisch @ 2008-05-19 16:10 UTC (permalink / raw)
  To: Kevin Hao; +Cc: venkatesh.pallipadi, bob.picco, mingo, tglx, linux-kernel

Kevin Hao wrote:
> +	for (irq = find_first_bit(&cap, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
> +		irq = find_next_bit(&cap, HPET_MAX_IRQ, 1 + irq)) {
> +		if (request_irq(irq, hpet_interrupt, irq_flags,
> +				devp->hd_name, (void *)devp))

This spams my log with interrupt sharing violations.  As long as we do
not know that the interrupt slot is empty, we need IRQF_PROBE_SHARED
here.

Another problem: the interrupt controller doesn't get correctly
initialized for some interrupt line that didn't already have some
routing:
| $ cat /proc/interrupts
|            CPU0
|   0:         63   IO-APIC-edge      timer
|   1:         96   IO-APIC-edge      i8042
|   2:          0    XT-PIC-XT        hpet2
|   6:          3   IO-APIC-edge      floppy
|   7:          0   IO-APIC-edge      parport0
|   8:          3   IO-APIC-edge      rtc
|   9:          0   IO-APIC-fasteoi   acpi
| ...

Additionally, I vaguely remember that on X86, there is some funny stuff
going on with interrupt lines 0, 2 and 8 which means that the interrupt
number passed to request_irq() is not necessarily identical to the
hardware interrupt line.

I don't know which of these problems is responsible, or if I'm totally
wrong, but on my machine, interrupts from hpet2 do not arrive.


Regards,
Clemens

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-19 16:10     ` Clemens Ladisch
@ 2008-05-19 21:21       ` Maciej W. Rozycki
  2008-05-20  9:03       ` Kevin Hao
  1 sibling, 0 replies; 20+ messages in thread
From: Maciej W. Rozycki @ 2008-05-19 21:21 UTC (permalink / raw)
  To: Clemens Ladisch
  Cc: Kevin Hao, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel

On Mon, 19 May 2008, Clemens Ladisch wrote:

> Another problem: the interrupt controller doesn't get correctly
> initialized for some interrupt line that didn't already have some
> routing:
> | $ cat /proc/interrupts
> |            CPU0
> |   0:         63   IO-APIC-edge      timer
> |   1:         96   IO-APIC-edge      i8042
> |   2:          0    XT-PIC-XT        hpet2
> |   6:          3   IO-APIC-edge      floppy
> |   7:          0   IO-APIC-edge      parport0
> |   8:          3   IO-APIC-edge      rtc
> |   9:          0   IO-APIC-fasteoi   acpi
> | ...

 IRQ2 cannot be wired to the legacy 8259A chips, because this line is
taken for the cascade from the slave to the master.  If you know for sure
that the HPET2 can be routed to the an otherwise unused input of the I/O
APIC, then you can use add_pin_to_irq() to route the entry manually.

> Additionally, I vaguely remember that on X86, there is some funny stuff
> going on with interrupt lines 0, 2 and 8 which means that the interrupt
> number passed to request_irq() is not necessarily identical to the
> hardware interrupt line.

 You are correct as far as input lines INT0 and INT2 of the I/O APIC are
concerned.  INT8 is not generally a problem except from some systems where
the polarity used to be recorded incorrectly in the BIOS tables (hardware
can be configured for either).  With INT0 and INT2 the following is
usually the case.

 INT0 is wired to the output of the master 8259A legacy controller.  It is
either configured as an ExtINTA interrupt or disabled by default
altogether (and the LINT0 input of the local APIC of the bootstrap
processor used instead).  Even if some additional logic is present in the
system so that another source can be routed to this line and the 8259A is
quiesced, sharing is probably impossible, because the output of the 8259A
is traditionally active high.

 INT2 is wired to the output of the 8254 timer (and in some more recent
systems shared with the HPET0).  This is the line that is referred to as
IRQ0 above.  This is because in an ACPI-based system the IRQ numbers refer
to lines as defined in ACPI tables, which may not necessarily identity-map
to I/O APIC input lines.

 Then the reasons for routing INT0 and INT2 like this are generally
historical and date back to the old Multi-Processor Specification.  There
may be systems that differ, but care must be taken and the correct
configuration table consulted.

  Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-19 16:10     ` Clemens Ladisch
  2008-05-19 21:21       ` Maciej W. Rozycki
@ 2008-05-20  9:03       ` Kevin Hao
  2008-05-20 15:46         ` Maciej W. Rozycki
  1 sibling, 1 reply; 20+ messages in thread
From: Kevin Hao @ 2008-05-20  9:03 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: venkatesh.pallipadi, bob.picco, mingo, tglx, linux-kernel

On Mon, 2008-05-19 at 18:10 +0200, Clemens Ladisch wrote:
> Kevin Hao wrote:
> > +	for (irq = find_first_bit(&cap, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
> > +		irq = find_next_bit(&cap, HPET_MAX_IRQ, 1 + irq)) {
> > +		if (request_irq(irq, hpet_interrupt, irq_flags,
> > +				devp->hd_name, (void *)devp))
> 
> This spams my log with interrupt sharing violations.  As long as we do
> not know that the interrupt slot is empty, we need IRQF_PROBE_SHARED
> here.

Ok, added.

> 
> Another problem: the interrupt controller doesn't get correctly
> initialized for some interrupt line that didn't already have some
> routing:
> | $ cat /proc/interrupts
> |            CPU0
> |   0:         63   IO-APIC-edge      timer
> |   1:         96   IO-APIC-edge      i8042
> |   2:          0    XT-PIC-XT        hpet2
> |   6:          3   IO-APIC-edge      floppy
> |   7:          0   IO-APIC-edge      parport0
> |   8:          3   IO-APIC-edge      rtc
> |   9:          0   IO-APIC-fasteoi   acpi
> | ...
> 
> Additionally, I vaguely remember that on X86, there is some funny stuff
> going on with interrupt lines 0, 2 and 8 which means that the interrupt
> number passed to request_irq() is not necessarily identical to the
> hardware interrupt line.
> 
> I don't know which of these problems is responsible, or if I'm totally
> wrong, but on my machine, interrupts from hpet2 do not arrive.
> 

We can simply skip these special IRQ. :-)
Does anyone has a better solution?

----
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 0fdc627..b04a15d 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -390,6 +390,11 @@ static int hpet_timer_get_irq(struct hpet_dev *devp)
 	struct hpets *hpetp;
 	unsigned long cap, irq_flags;
 	int irq;
+	/*
+	 * skip IRQ0, IRQ2, IRQ8 because which is always used by some
+	 * legacy device
+	 */
+	unsigned long skip_irq = (1 << 0) | (1 << 2) | (1 << 8);
 
 	timer = devp->hd_timer;
 	hpet = devp->hd_hpet;
@@ -411,6 +416,9 @@ static int hpet_timer_get_irq(struct hpet_dev *devp)
 
 	cap = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK)
 				 >> Tn_INT_ROUTE_CAP_SHIFT;
+	cap &= ~skip_irq;
+
+	irq_flags |= IRQF_PROBE_SHARED;
 
 	for (irq = find_first_bit(&cap, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
 		irq = find_next_bit(&cap, HPET_MAX_IRQ, 1 + irq)) {

---
Best Regards,
Kevin

> 
> Regards,
> Clemens

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-20  9:03       ` Kevin Hao
@ 2008-05-20 15:46         ` Maciej W. Rozycki
  2008-05-21  8:28           ` Clemens Ladisch
  0 siblings, 1 reply; 20+ messages in thread
From: Maciej W. Rozycki @ 2008-05-20 15:46 UTC (permalink / raw)
  To: Kevin Hao
  Cc: Clemens Ladisch, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel

On Tue, 20 May 2008, Kevin Hao wrote:

> We can simply skip these special IRQ. :-)
> Does anyone has a better solution?

 Hmm, you probably want to skip all lines that are edge-triggered.  
Otherwise you may have problems with sharing.  Drivers for devices used
with these edge-triggered lines may have special provisions to permit
sharing in a crafted way in special arrangements (cf. the 8250 serial or
the IDE driver), but that may not work in a generic way with a different
driver in the scenario.  And the polarity may be wrong too --
edge-triggered lines are often active-high, because it's fine with them.

 This driver is quite platform-specific -- how about instead of blindly
probing for interrupt lines, you actually allocate one somehow in platform
code?  For example the x86 platform could select an otherwise unused
interrupt line for you -- having routed all the legacy and PCI devices,
these systems quite frequently are left with a couple of otherwise unused
I/O APIC inputs.  If not, sharing with a PCI interrupt line would be a
good choice.  AFAIK, except from 8254 and RTC emulation the HPET cannot be
used with the legacy 8259A interrupt controllers, so that is a non issue
(but platform will know to disable your driver then).

  Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-20 15:46         ` Maciej W. Rozycki
@ 2008-05-21  8:28           ` Clemens Ladisch
  2008-05-22  3:47             ` Maciej W. Rozycki
  0 siblings, 1 reply; 20+ messages in thread
From: Clemens Ladisch @ 2008-05-21  8:28 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Kevin Hao, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

Maciej W. Rozycki wrote:
> On Tue, 20 May 2008, Kevin Hao wrote:
> > We can simply skip these special IRQ. :-)
> > Does anyone has a better solution?
>
>  Hmm, you probably want to skip all lines that are edge-triggered.
> Otherwise you may have problems with sharing.

HPET interrupts can be either edge or level triggered.  Probably we
should modify it according to the type of the interrupt line we're
trying to grab.

> Drivers for devices used with these edge-triggered lines may have
> special provisions to permit sharing ...

An edge-triggered HPET interrupt line is not shared (we set IRQF_SHARED
only if the register says that it's level triggered).

>  This driver is quite platform-specific -- how about instead of blindly
> probing for interrupt lines, you actually allocate one somehow in platform
> code?

I don't have much of a clue about that "somehow", but this sound like a
good idea.  ;-)

I think hpet_reserve_platform_timers() might be the place for this.

It gets called from hpet_late_init(), which is a fs_initcall, so I think
we should be careful not to grab some unsharable interrupt that might be
needed by some ISA device whose driver is initialized later.
(This was a bug in 2.6.25-rc5: <http://bugzilla.kernel.org/show_bug.cgi?id=10382>)


Regards,
Clemens

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-21  8:28           ` Clemens Ladisch
@ 2008-05-22  3:47             ` Maciej W. Rozycki
  2008-05-22  7:27               ` Kevin Hao
  0 siblings, 1 reply; 20+ messages in thread
From: Maciej W. Rozycki @ 2008-05-22  3:47 UTC (permalink / raw)
  To: Clemens Ladisch
  Cc: Kevin Hao, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

On Wed, 21 May 2008, Clemens Ladisch wrote:

> >  Hmm, you probably want to skip all lines that are edge-triggered.
> > Otherwise you may have problems with sharing.
> 
> HPET interrupts can be either edge or level triggered.  Probably we
> should modify it according to the type of the interrupt line we're
> trying to grab.

 Edge-triggered lines are generally associated with legacy devices.  It
may not be possible to grab one without disturbing the other device.

> >  This driver is quite platform-specific -- how about instead of blindly
> > probing for interrupt lines, you actually allocate one somehow in platform
> > code?
> 
> I don't have much of a clue about that "somehow", but this sound like a
> good idea.  ;-)
> 
> I think hpet_reserve_platform_timers() might be the place for this.
> 
> It gets called from hpet_late_init(), which is a fs_initcall, so I think
> we should be careful not to grab some unsharable interrupt that might be
> needed by some ISA device whose driver is initialized later.
> (This was a bug in 2.6.25-rc5: <http://bugzilla.kernel.org/show_bug.cgi?id=10382>)

 I have had a look at the relevant areas of ACPI and HPET specs and it
looks pretty straightforward, although not all the information is recorded
in system tables.  Essentially you are free to choose an arbitrary
interrupt supported by the HPET -- which you can find in the timer's
routing capability (as the proposed patch is doing).

 However you are right you really want to select one which does not
conflict with a legacy device, so it's probably best to avoid the legacy
range altogether (worth noting as for example the system I have handy has
the capability of its timer #2 set to 0x00f00800 -- here IRQ11 may not be
safe to use) and then you have to check how many inputs beyond the legacy
range are supported by the I/O APICs in the system -- you can have a look
at mp_find_ioapic() to see how obtain that information and then you can
call mp_register_gsi() on the interrupt line selected like this to set up
routing in the I/O APIC as necessary.  Level-triggered mode has to be used
as the resulting interrupt entry may happen to be shared with a PCI
interrupt.

 Though I have just noticed there is something wrong with the spec -- it
says that "The interrupts are all active high." which precludes sharing,
hmm... -- broken spec?  If hardware designers actually followed it in this
respect (I wouldn't be surprised as for some of them software is abstract
enough a concept not to be bothered with, and then it is a spec after
all), then I am afraid we need to have a way to get an exclusive
reservation of an I/O APIC line.  It could be tough with a system using
fixed routing and reusing a legacy IRQ might be the only choice -- if
supported by the HPET router, that is.

 Of course if the HPET supports MSI delivery and the kernel configuration
has it enabled, then you can avoid all the hassle with finding an
available IRQ line altogether.

  Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-22  3:47             ` Maciej W. Rozycki
@ 2008-05-22  7:27               ` Kevin Hao
  2008-05-22 15:25                 ` Maciej W. Rozycki
  0 siblings, 1 reply; 20+ messages in thread
From: Kevin Hao @ 2008-05-22  7:27 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Clemens Ladisch, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

On Thu, 2008-05-22 at 04:47 +0100, Maciej W. Rozycki wrote:
> On Wed, 21 May 2008, Clemens Ladisch wrote:
> 
> > >  Hmm, you probably want to skip all lines that are edge-triggered.
> > > Otherwise you may have problems with sharing.
> > 
> > HPET interrupts can be either edge or level triggered.  Probably we
> > should modify it according to the type of the interrupt line we're
> > trying to grab.
> 
>  Edge-triggered lines are generally associated with legacy devices.  It
> may not be possible to grab one without disturbing the other device.
> 
> > >  This driver is quite platform-specific -- how about instead of blindly
> > > probing for interrupt lines, you actually allocate one somehow in platform
> > > code?
> > 
> > I don't have much of a clue about that "somehow", but this sound like a
> > good idea.  ;-)
> > 
> > I think hpet_reserve_platform_timers() might be the place for this.
> > 
> > It gets called from hpet_late_init(), which is a fs_initcall, so I think
> > we should be careful not to grab some unsharable interrupt that might be
> > needed by some ISA device whose driver is initialized later.
> > (This was a bug in 2.6.25-rc5: <http://bugzilla.kernel.org/show_bug.cgi?id=10382>)
> 
>  I have had a look at the relevant areas of ACPI and HPET specs and it
> looks pretty straightforward, although not all the information is recorded
> in system tables.  Essentially you are free to choose an arbitrary
> interrupt supported by the HPET -- which you can find in the timer's
> routing capability (as the proposed patch is doing).
> 
>  However you are right you really want to select one which does not
> conflict with a legacy device, so it's probably best to avoid the legacy
> range altogether (worth noting as for example the system I have handy has
> the capability of its timer #2 set to 0x00f00800 -- here IRQ11 may not be
> safe to use)

But if we avoid all the legacy range, the hpet timer will have no chance
to work on a host using legacy PIC.

>  and then you have to check how many inputs beyond the legacy
> range are supported by the I/O APICs in the system -- you can have a look
> at mp_find_ioapic() to see how obtain that information and then you can
> call mp_register_gsi() on the interrupt line selected like this to set up
> routing in the I/O APIC as necessary.  Level-triggered mode has to be used
> as the resulting interrupt entry may happen to be shared with a PCI
> interrupt.

Yes, we should setup routing in the I/O APIC and use level-triggered
mode. I think it's better to use acpi_register_gsi than mp_register_gsi.
Is that right?

Best Regards,
Kevin

> 
>  Though I have just noticed there is something wrong with the spec -- it
> says that "The interrupts are all active high." which precludes sharing,
> hmm... -- broken spec?  If hardware designers actually followed it in this
> respect (I wouldn't be surprised as for some of them software is abstract
> enough a concept not to be bothered with, and then it is a spec after
> all), then I am afraid we need to have a way to get an exclusive
> reservation of an I/O APIC line.  It could be tough with a system using
> fixed routing and reusing a legacy IRQ might be the only choice -- if
> supported by the HPET router, that is.
> 
>  Of course if the HPET supports MSI delivery and the kernel configuration
> has it enabled, then you can avoid all the hassle with finding an
> available IRQ line altogether.
> 
>   Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-22  7:27               ` Kevin Hao
@ 2008-05-22 15:25                 ` Maciej W. Rozycki
  2008-05-28 10:42                   ` Kevin Hao
  0 siblings, 1 reply; 20+ messages in thread
From: Maciej W. Rozycki @ 2008-05-22 15:25 UTC (permalink / raw)
  To: Kevin Hao
  Cc: Clemens Ladisch, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

On Thu, 22 May 2008, Kevin Hao wrote:

> But if we avoid all the legacy range, the hpet timer will have no chance
> to work on a host using legacy PIC.

 It's not meant to be wired to the legacy PIC anyway (except from the
timers #0 and #1 in some configurations, meant to emulate timer interrupts
of the 8254 and the RTC), though I can imagine such a non-standard
extension.

> Yes, we should setup routing in the I/O APIC and use level-triggered
> mode. I think it's better to use acpi_register_gsi than mp_register_gsi.
> Is that right?

 It sounds right to me.

  Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-22 15:25                 ` Maciej W. Rozycki
@ 2008-05-28 10:42                   ` Kevin Hao
  2008-05-29  3:13                     ` Maciej W. Rozycki
  0 siblings, 1 reply; 20+ messages in thread
From: Kevin Hao @ 2008-05-28 10:42 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Clemens Ladisch, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

Sorry for the delays.

I have revised this patch according to Maciej & Clemens suggestions.
The modifications include:

1. Assign a irq to the timer when we open the timer device. I think it's
better than do it in platform code. So we will have little impact on
other device.

2. Set IRQ routing entry for the irq we select.

3. If we in PIC mode, we skip all the well known legacy IRQ. And in io
apic we skip all the legacy IRQ.

4. Use level triggered mode by default.

BTW, Maciej. I am not familiar with ACPI subsystem. But I think the 
acpi_register_gsi should return -1 if mp_find_ioapic return error.
Is that right? If you also think so, I will make a patch for that.

---
 drivers/char/hpet.c  |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hpet.h |    3 +-
 2 files changed, 63 insertions(+), 1 deletion(-)
---
commit fa8e14bc3abb93832fbc9b7f86da0d2cf5b3b7a7
Author: Kevin Hao <kexin.hao@windriver.com>
Date:   Wed May 28 13:28:20 2008 +0800

    HPET timer's IRQ is 0 by default. So we have to select which irq
    will be used by these timers. We wait to set the timer's irq until
    we really open it in order to reduce the chance of conflicting with
    other device.
    
    Signed-off-by: Kevin Hao <kexin.hao@windriver.com>

diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index e7fb0bc..94dbfdc 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -184,6 +184,65 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static void hpet_timer_set_irq(struct hpet_dev *devp)
+{
+	unsigned long v;
+	int irq, gsi;
+	struct hpet_timer __iomem *timer;
+
+	spin_lock_irq(&hpet_lock);
+	if (devp->hd_hdwirq) {
+		spin_unlock_irq(&hpet_lock);
+		return;
+	}
+
+	timer = devp->hd_timer;
+
+	/* we prefer level triggered mode */
+	v = readl(&timer->hpet_config);
+	if (!(v & Tn_INT_TYPE_CNF_MASK)) {
+		v |= Tn_INT_TYPE_CNF_MASK;
+		writel(v, &timer->hpet_config);
+	}
+	spin_unlock_irq(&hpet_lock);
+
+	v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK)
+				 >> Tn_INT_ROUTE_CAP_SHIFT;
+
+	/*
+	 * In PIC mode, skip IRQ0-4, IRQ6-8, IRQ12-15 which is always used by
+	 * legacy device. In IO APIC mode, we skip all the legacy IRQS.
+	 */
+	if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
+		v &= ~0xf1df;
+	else
+		v &= ~0xffff;
+
+	for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
+		irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
+
+		if (irq >= NR_IRQS) {
+			irq = HPET_MAX_IRQ;
+			break;
+		}
+
+		gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
+					ACPI_ACTIVE_LOW);
+		if (gsi > 0)
+			break;
+	}
+
+	if  (irq < HPET_MAX_IRQ) {
+		spin_lock_irq(&hpet_lock);
+		v = readl(&timer->hpet_config);
+		v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
+		writel(v, &timer->hpet_config);
+		devp->hd_hdwirq = gsi;
+		spin_unlock_irq(&hpet_lock);
+	}
+	return;
+}
+
 static int hpet_open(struct inode *inode, struct file *file)
 {
 	struct hpet_dev *devp;
@@ -215,6 +274,8 @@ static int hpet_open(struct inode *inode, struct file *file)
 	devp->hd_flags |= HPET_OPEN;
 	spin_unlock_irq(&hpet_lock);
 
+	hpet_timer_set_irq(devp);
+
 	return 0;
 }
 
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 2dc29ce..440ca72 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -37,6 +37,7 @@ struct hpet {
 #define	hpet_compare	_u1._hpet_compare
 
 #define	HPET_MAX_TIMERS	(32)
+#define HPET_MAX_IRQ	(32)
 
 /*
  * HPET general capabilities register
@@ -64,7 +65,7 @@ struct hpet {
  */
 
 #define	Tn_INT_ROUTE_CAP_MASK		(0xffffffff00000000ULL)
-#define	Tn_INI_ROUTE_CAP_SHIFT		(32UL)
+#define	Tn_INT_ROUTE_CAP_SHIFT		(32UL)
 #define	Tn_FSB_INT_DELCAP_MASK		(0x8000UL)
 #define	Tn_FSB_INT_DELCAP_SHIFT		(15)
 #define	Tn_FSB_EN_CNF_MASK		(0x4000UL)
---

Best Regards,
Kevin


On Thu, 2008-05-22 at 16:25 +0100, Maciej W. Rozycki wrote: 
> On Thu, 22 May 2008, Kevin Hao wrote:
> 
> > But if we avoid all the legacy range, the hpet timer will have no chance
> > to work on a host using legacy PIC.
> 
>  It's not meant to be wired to the legacy PIC anyway (except from the
> timers #0 and #1 in some configurations, meant to emulate timer interrupts
> of the 8254 and the RTC), though I can imagine such a non-standard
> extension.
> 
> > Yes, we should setup routing in the I/O APIC and use level-triggered
> > mode. I think it's better to use acpi_register_gsi than mp_register_gsi.
> > Is that right?
> 
>  It sounds right to me.
> 
>   Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-28 10:42                   ` Kevin Hao
@ 2008-05-29  3:13                     ` Maciej W. Rozycki
  2008-05-29 10:41                       ` Kevin Hao
  0 siblings, 1 reply; 20+ messages in thread
From: Maciej W. Rozycki @ 2008-05-29  3:13 UTC (permalink / raw)
  To: Kevin Hao
  Cc: Clemens Ladisch, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

On Wed, 28 May 2008, Kevin Hao wrote:

> BTW, Maciej. I am not familiar with ACPI subsystem. But I think the 
> acpi_register_gsi should return -1 if mp_find_ioapic return error.
> Is that right? If you also think so, I will make a patch for that.

 Well, the interface is documented in the sources -- I do not feel like
reading through all the execution paths to see whether the implementation
matches though. ;)

 A few comments below -- I may not have time available to throw your piece 
of code at a piece of hardware though.

> +	/* we prefer level triggered mode */
> +	v = readl(&timer->hpet_config);
> +	if (!(v & Tn_INT_TYPE_CNF_MASK)) {
> +		v |= Tn_INT_TYPE_CNF_MASK;
> +		writel(v, &timer->hpet_config);
> +	}

 Please note that when routing through the 8259A you need to match the
trigger mode set for the respective input.  It is normally set in the ELCR
register in the hardware and should be recorded in the ACPI interrupt
source tables too -- the default for IRQ0-15 is edge-triggered, active
high, unless overridden.

> +	v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK)
> +				 >> Tn_INT_ROUTE_CAP_SHIFT;

 The operator should be at the end of the first line IMHO.

> +	/*
> +	 * In PIC mode, skip IRQ0-4, IRQ6-8, IRQ12-15 which is always used by
> +	 * legacy device. In IO APIC mode, we skip all the legacy IRQS.
> +	 */

 Quite reasonable assumption IMO, but again -- I'd expect the information 
about legacy devices present on these lines to be recorded in ACPI tables.  
Note that IRQ9 is used for the SCI -- I am not sure if that's a good 
choice for sharing.

> +		gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
> +					ACPI_ACTIVE_LOW);

 I am assuming you have verified ACPI_ACTIVE_LOW works here, contrary to 
the HPET spec.

> +	if  (irq < HPET_MAX_IRQ) {

 Single space here.

> @@ -37,6 +37,7 @@ struct hpet {
>  #define	hpet_compare	_u1._hpet_compare
>  
>  #define	HPET_MAX_TIMERS	(32)
> +#define HPET_MAX_IRQ	(32)

 Tab here for consistency with the others?

 Otherwise no obvious problems.

  Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-29  3:13                     ` Maciej W. Rozycki
@ 2008-05-29 10:41                       ` Kevin Hao
  2008-05-29 14:32                         ` Maciej W. Rozycki
  0 siblings, 1 reply; 20+ messages in thread
From: Kevin Hao @ 2008-05-29 10:41 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Clemens Ladisch, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

On Thu, 2008-05-29 at 04:13 +0100, Maciej W. Rozycki wrote: 
> On Wed, 28 May 2008, Kevin Hao wrote:
> 
> > BTW, Maciej. I am not familiar with ACPI subsystem. But I think the 
> > acpi_register_gsi should return -1 if mp_find_ioapic return error.
> > Is that right? If you also think so, I will make a patch for that.
> 
>  Well, the interface is documented in the sources -- I do not feel like
> reading through all the execution paths to see whether the implementation
> matches though. ;)
> 
>  A few comments below -- I may not have time available to throw your piece 
> of code at a piece of hardware though.
> 
> > +	/* we prefer level triggered mode */
> > +	v = readl(&timer->hpet_config);
> > +	if (!(v & Tn_INT_TYPE_CNF_MASK)) {
> > +		v |= Tn_INT_TYPE_CNF_MASK;
> > +		writel(v, &timer->hpet_config);
> > +	}
> 
>  Please note that when routing through the 8259A you need to match the
> trigger mode set for the respective input.  It is normally set in the ELCR
> register in the hardware and should be recorded in the ACPI interrupt
> source tables too -- the default for IRQ0-15 is edge-triggered, active
> high, unless overridden.

The IRQ trigger mode is set to level by acpi_register_gsi in PIC mode.
And I have tested it on a host using legacy PIC. It works well.

Yes, we should record these information in ACPI interrupt source table.
And I have noticed that a patch has been made to update mptable. 
http://lkml.org/lkml/2008/5/25/255

We can use mp_config_acpi_gsi to setup route table. But now can we add
somethings like "FIXME: setup interrupt source table" and wait for that
patch to be merged?

> 
> > +	v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK)
> > +				 >> Tn_INT_ROUTE_CAP_SHIFT;
> 
>  The operator should be at the end of the first line IMHO.

Ok, fix it.

> 
> > +	/*
> > +	 * In PIC mode, skip IRQ0-4, IRQ6-8, IRQ12-15 which is always used by
> > +	 * legacy device. In IO APIC mode, we skip all the legacy IRQS.
> > +	 */
> 
>  Quite reasonable assumption IMO, but again -- I'd expect the information 
> about legacy devices present on these lines to be recorded in ACPI tables.  
> Note that IRQ9 is used for the SCI -- I am not sure if that's a good 
> choice for sharing.

Add IRQ9 to the skipping IRQS.

> 
> > +		gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
> > +					ACPI_ACTIVE_LOW);
> 
>  I am assuming you have verified ACPI_ACTIVE_LOW works here, contrary to 
> the HPET spec.

Yes, It can work with other PCI device in ACPI_ACTIVE_LOW polarity.

> 
> > +	if  (irq < HPET_MAX_IRQ) {
> 
>  Single space here.

Ok, deleted.

> 
> > @@ -37,6 +37,7 @@ struct hpet {
> >  #define	hpet_compare	_u1._hpet_compare
> >  
> >  #define	HPET_MAX_TIMERS	(32)
> > +#define HPET_MAX_IRQ	(32)
> 
>  Tab here for consistency with the others?

Ok, fix it.

Thanks for your comments.

---
    HPET timer's IRQ is 0 by default. So we have to select which irq
    will be used by these timers. We wait to set the timer's irq until
    we really open it in order to reduce the chance of conflicting with
    other device.
    
    Signed-off-by: Kevin Hao <kexin.hao@windriver.com>
---
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index e7fb0bc..c9bf5d4 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -184,6 +184,67 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static void hpet_timer_set_irq(struct hpet_dev *devp)
+{
+	unsigned long v;
+	int irq, gsi;
+	struct hpet_timer __iomem *timer;
+
+	spin_lock_irq(&hpet_lock);
+	if (devp->hd_hdwirq) {
+		spin_unlock_irq(&hpet_lock);
+		return;
+	}
+
+	timer = devp->hd_timer;
+
+	/* we prefer level triggered mode */
+	v = readl(&timer->hpet_config);
+	if (!(v & Tn_INT_TYPE_CNF_MASK)) {
+		v |= Tn_INT_TYPE_CNF_MASK;
+		writel(v, &timer->hpet_config);
+	}
+	spin_unlock_irq(&hpet_lock);
+
+	v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >>
+				 Tn_INT_ROUTE_CAP_SHIFT;
+
+	/*
+	 * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by
+	 * legacy device. In IO APIC mode, we skip all the legacy IRQS.
+	 */
+	if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
+		v &= ~0xf3df;
+	else
+		v &= ~0xffff;
+
+	for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
+		irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
+
+		if (irq >= NR_IRQS) {
+			irq = HPET_MAX_IRQ;
+			break;
+		}
+
+		gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
+					ACPI_ACTIVE_LOW);
+		if (gsi > 0)
+			break;
+
+		/* FIXME: Setup interrupt source table */
+	}
+
+	if (irq < HPET_MAX_IRQ) {
+		spin_lock_irq(&hpet_lock);
+		v = readl(&timer->hpet_config);
+		v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
+		writel(v, &timer->hpet_config);
+		devp->hd_hdwirq = gsi;
+		spin_unlock_irq(&hpet_lock);
+	}
+	return;
+}
+
 static int hpet_open(struct inode *inode, struct file *file)
 {
 	struct hpet_dev *devp;
@@ -215,6 +276,8 @@ static int hpet_open(struct inode *inode, struct file *file)
 	devp->hd_flags |= HPET_OPEN;
 	spin_unlock_irq(&hpet_lock);
 
+	hpet_timer_set_irq(devp);
+
 	return 0;
 }
 
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 2dc29ce..6d2626b 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -37,6 +37,7 @@ struct hpet {
 #define	hpet_compare	_u1._hpet_compare
 
 #define	HPET_MAX_TIMERS	(32)
+#define	HPET_MAX_IRQ	(32)
 
 /*
  * HPET general capabilities register
@@ -64,7 +65,7 @@ struct hpet {
  */
 
 #define	Tn_INT_ROUTE_CAP_MASK		(0xffffffff00000000ULL)
-#define	Tn_INI_ROUTE_CAP_SHIFT		(32UL)
+#define	Tn_INT_ROUTE_CAP_SHIFT		(32UL)
 #define	Tn_FSB_INT_DELCAP_MASK		(0x8000UL)
 #define	Tn_FSB_INT_DELCAP_SHIFT		(15)
 #define	Tn_FSB_EN_CNF_MASK		(0x4000UL)
---

Best Regards,
Kevin

> 
>  Otherwise no obvious problems.
> 
>   Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-29 10:41                       ` Kevin Hao
@ 2008-05-29 14:32                         ` Maciej W. Rozycki
  2008-05-30  5:32                           ` Kevin Hao
  0 siblings, 1 reply; 20+ messages in thread
From: Maciej W. Rozycki @ 2008-05-29 14:32 UTC (permalink / raw)
  To: Kevin Hao
  Cc: Clemens Ladisch, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

On Thu, 29 May 2008, Kevin Hao wrote:

> The IRQ trigger mode is set to level by acpi_register_gsi in PIC mode.
> And I have tested it on a host using legacy PIC. It works well.

 It may work by chance.  All what the code in question guarantees is:

int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
	*irq = gsi;
	return 0;
}

int acpi_register_gsi(u32 gsi, int triggering, int polarity)
{
	unsigned int irq;
	unsigned int plat_gsi = gsi;

	acpi_gsi_to_irq(plat_gsi, &irq);
	return irq;
}

CONFIG_PCI is optional for the x86 platform.  You could argue this is a
bug in acpi_register_gsi() and I tend to agree -- I think the existence of
the ELCR is implied for ACPI-compliant systems, though I am happy to be
corrected.  The ACPI spec does not mention the register, but quotes:  
"Existing industry standard register interfaces to: CMOS, PIC, PITs, ..."

 Anyway, blindly attaching to an IRQ line is not a terribly good idea as
there may be an edge-triggered line from a device wired there after all.  
For example many LPC SuperIO chips have configurable IRQ resources -- the
parallel port can use either IRQ5 or IRQ7 (but not both at a time).  OTOH
IRQ6 may be free after all as floppy drives become rare.  Only IRQ10 and
IRQ11 are probably safe to be assumed free in systems with no ISA slots,
but then again, I may have missed something.  Hopefully there are no true
PCI-ISA bridges with the HPET implemented -- I have checked a couple of 
datasheets for ACPI-compliant PCI-ISA bridges (such as the PIIX4) that I 
have handy and none of them implements the HPET.

> >  I am assuming you have verified ACPI_ACTIVE_LOW works here, contrary to 
> > the HPET spec.
> 
> Yes, It can work with other PCI device in ACPI_ACTIVE_LOW polarity.

 Good to know.  Thanks for verifying this.

  Maciej

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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-29 14:32                         ` Maciej W. Rozycki
@ 2008-05-30  5:32                           ` Kevin Hao
  2008-06-02  9:35                             ` Ingo Molnar
  0 siblings, 1 reply; 20+ messages in thread
From: Kevin Hao @ 2008-05-30  5:32 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Clemens Ladisch, venkatesh.pallipadi, bob.picco, mingo, tglx,
	linux-kernel, Balaji Rao

On Thu, 2008-05-29 at 15:32 +0100, Maciej W. Rozycki wrote:

> CONFIG_PCI is optional for the x86 platform.  You could argue this is a
> bug in acpi_register_gsi() and I tend to agree -- I think the existence of
> the ELCR is implied for ACPI-compliant systems, though I am happy to be
> corrected.  The ACPI spec does not mention the register, but quotes:  
> "Existing industry standard register interfaces to: CMOS, PIC, PITs, ..."

Oh, I overlook the existence of CONFIG_PCI.

After look into the code, I think we should add a acpi_pic_set_trigger
to replace eisa_set_level_irq and remove CONFIG_PCI dependency.

> 
>  Anyway, blindly attaching to an IRQ line is not a terribly good idea as
> there may be an edge-triggered line from a device wired there after all. 

Yes, I agree with you. But at present we have not a better way to
resolve this problem. 

Thanks,
Kevin


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

* Re: [PATCH] x86: Get irq for hpet timer
  2008-05-30  5:32                           ` Kevin Hao
@ 2008-06-02  9:35                             ` Ingo Molnar
  0 siblings, 0 replies; 20+ messages in thread
From: Ingo Molnar @ 2008-06-02  9:35 UTC (permalink / raw)
  To: Kevin Hao
  Cc: Maciej W. Rozycki, Clemens Ladisch, venkatesh.pallipadi,
	bob.picco, mingo, tglx, linux-kernel, Balaji Rao


* Kevin Hao <kexin.hao@windriver.com> wrote:

> >  Anyway, blindly attaching to an IRQ line is not a terribly good 
> > idea as there may be an edge-triggered line from a device wired 
> > there after all.
> 
> Yes, I agree with you. But at present we have not a better way to 
> resolve this problem.

i've applied your patch for more testing to tip/timers/hpet. Thanks,

	Ingo

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

end of thread, other threads:[~2008-06-02  9:36 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-16  6:05 [PATCH] x86: Get irq for hpet timer Kevin Hao
2008-05-16  7:53 ` Balaji Rao R
2008-05-16  8:03   ` Kevin Hao
2008-05-16  8:30     ` Balaji Rao
2008-05-16  8:46 ` Clemens Ladisch
2008-05-16  9:14   ` Kevin Hao
2008-05-19 16:10     ` Clemens Ladisch
2008-05-19 21:21       ` Maciej W. Rozycki
2008-05-20  9:03       ` Kevin Hao
2008-05-20 15:46         ` Maciej W. Rozycki
2008-05-21  8:28           ` Clemens Ladisch
2008-05-22  3:47             ` Maciej W. Rozycki
2008-05-22  7:27               ` Kevin Hao
2008-05-22 15:25                 ` Maciej W. Rozycki
2008-05-28 10:42                   ` Kevin Hao
2008-05-29  3:13                     ` Maciej W. Rozycki
2008-05-29 10:41                       ` Kevin Hao
2008-05-29 14:32                         ` Maciej W. Rozycki
2008-05-30  5:32                           ` Kevin Hao
2008-06-02  9:35                             ` Ingo Molnar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox