Skip to content

Commit

Permalink
[PATCH] hpet: allow shared interrupts
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Clemens Ladisch authored and Linus Torvalds committed Oct 31, 2005
1 parent 189e2dd commit 0d29086
Showing 1 changed file with 21 additions and 7 deletions.
28 changes: 21 additions & 7 deletions drivers/char/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ static struct hpets *hpets;
#define HPET_OPEN 0x0001
#define HPET_IE 0x0002 /* interrupt enabled */
#define HPET_PERIODIC 0x0004
#define HPET_SHARED_IRQ 0x0008

#if BITS_PER_LONG == 64
#define write_counter(V, MC) writeq(V, MC)
Expand Down Expand Up @@ -120,6 +121,11 @@ static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs)
unsigned long isr;

devp = data;
isr = 1 << (devp - devp->hd_hpets->hp_dev);

if ((devp->hd_flags & HPET_SHARED_IRQ) &&
!(isr & readl(&devp->hd_hpet->hpet_isr)))
return IRQ_NONE;

spin_lock(&hpet_lock);
devp->hd_irqdata++;
Expand All @@ -137,8 +143,8 @@ static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs)
&devp->hd_timer->hpet_compare);
}

isr = (1 << (devp - devp->hd_hpets->hp_dev));
writeq(isr, &devp->hd_hpet->hpet_isr);
if (devp->hd_flags & HPET_SHARED_IRQ)
writel(isr, &devp->hd_hpet->hpet_isr);
spin_unlock(&hpet_lock);

spin_lock(&hpet_task_lock);
Expand Down Expand Up @@ -375,15 +381,21 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
}

devp->hd_flags |= HPET_IE;

if (readl(&timer->hpet_config) & Tn_INT_TYPE_CNF_MASK)
devp->hd_flags |= HPET_SHARED_IRQ;
spin_unlock_irq(&hpet_lock);

irq = devp->hd_hdwirq;

if (irq) {
sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
unsigned long irq_flags;

if (request_irq
(irq, hpet_interrupt, SA_INTERRUPT, devp->hd_name, (void *)devp)) {
sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
irq_flags = devp->hd_flags & HPET_SHARED_IRQ
? SA_SHIRQ : SA_INTERRUPT;
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;
}
Expand Down Expand Up @@ -417,8 +429,10 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
}

isr = (1 << (devp - hpets->hp_dev));
writeq(isr, &hpet->hpet_isr);
if (devp->hd_flags & HPET_SHARED_IRQ) {
isr = 1 << (devp - hpets->hp_dev);
writel(isr, &hpet->hpet_isr);
}
writeq(g, &timer->hpet_config);
local_irq_restore(flags);

Expand Down

0 comments on commit 0d29086

Please sign in to comment.