aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Hao <kexin.hao@windriver.com>2008-05-29 06:41:04 -0400
committerIngo Molnar <mingo@elte.hu>2008-06-02 05:35:12 -0400
commit70ef6d595b6e51618a0cbe44b848d8c9db11a010 (patch)
tree78129b50ab2f76752d1012502d724a78ad7bc648
parente490517a039a99d692cb3a5561941b0a5f576172 (diff)
x86: get irq for hpet timer
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>
-rw-r--r--drivers/char/hpet.c63
-rw-r--r--include/linux/hpet.h3
2 files changed, 65 insertions, 1 deletions
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index e7fb0bca3667..c9bf5d44402d 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -184,6 +184,67 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
184 return IRQ_HANDLED; 184 return IRQ_HANDLED;
185} 185}
186 186
187static void hpet_timer_set_irq(struct hpet_dev *devp)
188{
189 unsigned long v;
190 int irq, gsi;
191 struct hpet_timer __iomem *timer;
192
193 spin_lock_irq(&hpet_lock);
194 if (devp->hd_hdwirq) {
195 spin_unlock_irq(&hpet_lock);
196 return;
197 }
198
199 timer = devp->hd_timer;
200
201 /* we prefer level triggered mode */
202 v = readl(&timer->hpet_config);
203 if (!(v & Tn_INT_TYPE_CNF_MASK)) {
204 v |= Tn_INT_TYPE_CNF_MASK;
205 writel(v, &timer->hpet_config);
206 }
207 spin_unlock_irq(&hpet_lock);
208
209 v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >>
210 Tn_INT_ROUTE_CAP_SHIFT;
211
212 /*
213 * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by
214 * legacy device. In IO APIC mode, we skip all the legacy IRQS.
215 */
216 if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
217 v &= ~0xf3df;
218 else
219 v &= ~0xffff;
220
221 for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
222 irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
223
224 if (irq >= NR_IRQS) {
225 irq = HPET_MAX_IRQ;
226 break;
227 }
228
229 gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
230 ACPI_ACTIVE_LOW);
231 if (gsi > 0)
232 break;
233
234 /* FIXME: Setup interrupt source table */
235 }
236
237 if (irq < HPET_MAX_IRQ) {
238 spin_lock_irq(&hpet_lock);
239 v = readl(&timer->hpet_config);
240 v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
241 writel(v, &timer->hpet_config);
242 devp->hd_hdwirq = gsi;
243 spin_unlock_irq(&hpet_lock);
244 }
245 return;
246}
247
187static int hpet_open(struct inode *inode, struct file *file) 248static int hpet_open(struct inode *inode, struct file *file)
188{ 249{
189 struct hpet_dev *devp; 250 struct hpet_dev *devp;
@@ -215,6 +276,8 @@ static int hpet_open(struct inode *inode, struct file *file)
215 devp->hd_flags |= HPET_OPEN; 276 devp->hd_flags |= HPET_OPEN;
216 spin_unlock_irq(&hpet_lock); 277 spin_unlock_irq(&hpet_lock);
217 278
279 hpet_timer_set_irq(devp);
280
218 return 0; 281 return 0;
219} 282}
220 283
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 2dc29ce6c8e4..6d2626b63a9a 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -37,6 +37,7 @@ struct hpet {
37#define hpet_compare _u1._hpet_compare 37#define hpet_compare _u1._hpet_compare
38 38
39#define HPET_MAX_TIMERS (32) 39#define HPET_MAX_TIMERS (32)
40#define HPET_MAX_IRQ (32)
40 41
41/* 42/*
42 * HPET general capabilities register 43 * HPET general capabilities register
@@ -64,7 +65,7 @@ struct hpet {
64 */ 65 */
65 66
66#define Tn_INT_ROUTE_CAP_MASK (0xffffffff00000000ULL) 67#define Tn_INT_ROUTE_CAP_MASK (0xffffffff00000000ULL)
67#define Tn_INI_ROUTE_CAP_SHIFT (32UL) 68#define Tn_INT_ROUTE_CAP_SHIFT (32UL)
68#define Tn_FSB_INT_DELCAP_MASK (0x8000UL) 69#define Tn_FSB_INT_DELCAP_MASK (0x8000UL)
69#define Tn_FSB_INT_DELCAP_SHIFT (15) 70#define Tn_FSB_INT_DELCAP_SHIFT (15)
70#define Tn_FSB_EN_CNF_MASK (0x4000UL) 71#define Tn_FSB_EN_CNF_MASK (0x4000UL)