diff options
-rw-r--r-- | drivers/char/hpet.c | 63 | ||||
-rw-r--r-- | include/linux/hpet.h | 3 |
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 | ||
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 | ||
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) |