diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2005-10-30 18:03:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-30 20:37:29 -0500 |
commit | 0d29086177aaa1e7d14e6ebb7fc067b3ca6d5c11 (patch) | |
tree | 1729f8bb3d6e7d1a1e061219fb01fecf90f183e4 /drivers/char/hpet.c | |
parent | 189e2dd1376c1eb2f3a717a15f1ed8c7d0b3811a (diff) |
[PATCH] hpet: allow shared interrupts
This patch adds support for shared HPET interrupts.
The driver previously acknowledged interrupts for both edge and level
interrupts, but didn't actually allow a shared interrupt in the latter case.
We use a new per-timer flag to save whether the timer's interrupt might be
shared, and use it to do the processing required for level interrupts only if
necessary.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Acked-by: Bob Picco <bob.picco@hp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/hpet.c')
-rw-r--r-- | drivers/char/hpet.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 85d39ff286c4..8e59639fb03c 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -90,6 +90,7 @@ static struct hpets *hpets; | |||
90 | #define HPET_OPEN 0x0001 | 90 | #define HPET_OPEN 0x0001 |
91 | #define HPET_IE 0x0002 /* interrupt enabled */ | 91 | #define HPET_IE 0x0002 /* interrupt enabled */ |
92 | #define HPET_PERIODIC 0x0004 | 92 | #define HPET_PERIODIC 0x0004 |
93 | #define HPET_SHARED_IRQ 0x0008 | ||
93 | 94 | ||
94 | #if BITS_PER_LONG == 64 | 95 | #if BITS_PER_LONG == 64 |
95 | #define write_counter(V, MC) writeq(V, MC) | 96 | #define write_counter(V, MC) writeq(V, MC) |
@@ -120,6 +121,11 @@ static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs) | |||
120 | unsigned long isr; | 121 | unsigned long isr; |
121 | 122 | ||
122 | devp = data; | 123 | devp = data; |
124 | isr = 1 << (devp - devp->hd_hpets->hp_dev); | ||
125 | |||
126 | if ((devp->hd_flags & HPET_SHARED_IRQ) && | ||
127 | !(isr & readl(&devp->hd_hpet->hpet_isr))) | ||
128 | return IRQ_NONE; | ||
123 | 129 | ||
124 | spin_lock(&hpet_lock); | 130 | spin_lock(&hpet_lock); |
125 | devp->hd_irqdata++; | 131 | devp->hd_irqdata++; |
@@ -137,8 +143,8 @@ static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs) | |||
137 | &devp->hd_timer->hpet_compare); | 143 | &devp->hd_timer->hpet_compare); |
138 | } | 144 | } |
139 | 145 | ||
140 | isr = (1 << (devp - devp->hd_hpets->hp_dev)); | 146 | if (devp->hd_flags & HPET_SHARED_IRQ) |
141 | writeq(isr, &devp->hd_hpet->hpet_isr); | 147 | writel(isr, &devp->hd_hpet->hpet_isr); |
142 | spin_unlock(&hpet_lock); | 148 | spin_unlock(&hpet_lock); |
143 | 149 | ||
144 | spin_lock(&hpet_task_lock); | 150 | spin_lock(&hpet_task_lock); |
@@ -375,15 +381,21 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) | |||
375 | } | 381 | } |
376 | 382 | ||
377 | devp->hd_flags |= HPET_IE; | 383 | devp->hd_flags |= HPET_IE; |
384 | |||
385 | if (readl(&timer->hpet_config) & Tn_INT_TYPE_CNF_MASK) | ||
386 | devp->hd_flags |= HPET_SHARED_IRQ; | ||
378 | spin_unlock_irq(&hpet_lock); | 387 | spin_unlock_irq(&hpet_lock); |
379 | 388 | ||
380 | irq = devp->hd_hdwirq; | 389 | irq = devp->hd_hdwirq; |
381 | 390 | ||
382 | if (irq) { | 391 | if (irq) { |
383 | sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); | 392 | unsigned long irq_flags; |
384 | 393 | ||
385 | if (request_irq | 394 | sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); |
386 | (irq, hpet_interrupt, SA_INTERRUPT, devp->hd_name, (void *)devp)) { | 395 | irq_flags = devp->hd_flags & HPET_SHARED_IRQ |
396 | ? SA_SHIRQ : SA_INTERRUPT; | ||
397 | if (request_irq(irq, hpet_interrupt, irq_flags, | ||
398 | devp->hd_name, (void *)devp)) { | ||
387 | printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); | 399 | printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); |
388 | irq = 0; | 400 | irq = 0; |
389 | } | 401 | } |
@@ -417,8 +429,10 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) | |||
417 | write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); | 429 | write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); |
418 | } | 430 | } |
419 | 431 | ||
420 | isr = (1 << (devp - hpets->hp_dev)); | 432 | if (devp->hd_flags & HPET_SHARED_IRQ) { |
421 | writeq(isr, &hpet->hpet_isr); | 433 | isr = 1 << (devp - hpets->hp_dev); |
434 | writel(isr, &hpet->hpet_isr); | ||
435 | } | ||
422 | writeq(g, &timer->hpet_config); | 436 | writeq(g, &timer->hpet_config); |
423 | local_irq_restore(flags); | 437 | local_irq_restore(flags); |
424 | 438 | ||