aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)