Skip to content

Commit

Permalink
x86: get irq for hpet timer
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Kevin Hao authored and Ingo Molnar committed Jun 2, 2008
1 parent e490517 commit 70ef6d5
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
63 changes: 63 additions & 0 deletions drivers/char/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion include/linux/hpet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 70ef6d5

Please sign in to comment.