diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/hpet.c | 63 |
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 | ||
187 | static 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 | |||
187 | static int hpet_open(struct inode *inode, struct file *file) | 248 | static 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 | ||