aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hpet.c
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 /drivers/char/hpet.c
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>
Diffstat (limited to 'drivers/char/hpet.c')
-rw-r--r--drivers/char/hpet.c63
1 files changed, 63 insertions, 0 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