aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2005-10-30 18:03:34 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-30 20:37:29 -0500
commit0d29086177aaa1e7d14e6ebb7fc067b3ca6d5c11 (patch)
tree1729f8bb3d6e7d1a1e061219fb01fecf90f183e4 /drivers/char
parent189e2dd1376c1eb2f3a717a15f1ed8c7d0b3811a (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')
-rw-r--r--drivers/char/hpet.c28
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