aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/hpet.c159
1 files changed, 89 insertions, 70 deletions
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index b3f5dbc6d880..f3cfb4c76125 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -53,6 +53,11 @@
53 53
54#define HPET_RANGE_SIZE 1024 /* from HPET spec */ 54#define HPET_RANGE_SIZE 1024 /* from HPET spec */
55 55
56
57/* WARNING -- don't get confused. These macros are never used
58 * to write the (single) counter, and rarely to read it.
59 * They're badly named; to fix, someday.
60 */
56#if BITS_PER_LONG == 64 61#if BITS_PER_LONG == 64
57#define write_counter(V, MC) writeq(V, MC) 62#define write_counter(V, MC) writeq(V, MC)
58#define read_counter(MC) readq(MC) 63#define read_counter(MC) readq(MC)
@@ -77,7 +82,7 @@ static struct clocksource clocksource_hpet = {
77 .rating = 250, 82 .rating = 250,
78 .read = read_hpet, 83 .read = read_hpet,
79 .mask = CLOCKSOURCE_MASK(64), 84 .mask = CLOCKSOURCE_MASK(64),
80 .mult = 0, /*to be caluclated*/ 85 .mult = 0, /* to be calculated */
81 .shift = 10, 86 .shift = 10,
82 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 87 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
83}; 88};
@@ -86,8 +91,6 @@ static struct clocksource *hpet_clocksource;
86 91
87/* A lock for concurrent access by app and isr hpet activity. */ 92/* A lock for concurrent access by app and isr hpet activity. */
88static DEFINE_SPINLOCK(hpet_lock); 93static DEFINE_SPINLOCK(hpet_lock);
89/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
90static DEFINE_SPINLOCK(hpet_task_lock);
91 94
92#define HPET_DEV_NAME (7) 95#define HPET_DEV_NAME (7)
93 96
@@ -99,7 +102,6 @@ struct hpet_dev {
99 unsigned long hd_irqdata; 102 unsigned long hd_irqdata;
100 wait_queue_head_t hd_waitqueue; 103 wait_queue_head_t hd_waitqueue;
101 struct fasync_struct *hd_async_queue; 104 struct fasync_struct *hd_async_queue;
102 struct hpet_task *hd_task;
103 unsigned int hd_flags; 105 unsigned int hd_flags;
104 unsigned int hd_irq; 106 unsigned int hd_irq;
105 unsigned int hd_hdwirq; 107 unsigned int hd_hdwirq;
@@ -173,11 +175,6 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
173 writel(isr, &devp->hd_hpet->hpet_isr); 175 writel(isr, &devp->hd_hpet->hpet_isr);
174 spin_unlock(&hpet_lock); 176 spin_unlock(&hpet_lock);
175 177
176 spin_lock(&hpet_task_lock);
177 if (devp->hd_task)
178 devp->hd_task->ht_func(devp->hd_task->ht_data);
179 spin_unlock(&hpet_task_lock);
180
181 wake_up_interruptible(&devp->hd_waitqueue); 178 wake_up_interruptible(&devp->hd_waitqueue);
182 179
183 kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN); 180 kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN);
@@ -185,6 +182,67 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
185 return IRQ_HANDLED; 182 return IRQ_HANDLED;
186} 183}
187 184
185static void hpet_timer_set_irq(struct hpet_dev *devp)
186{
187 unsigned long v;
188 int irq, gsi;
189 struct hpet_timer __iomem *timer;
190
191 spin_lock_irq(&hpet_lock);
192 if (devp->hd_hdwirq) {
193 spin_unlock_irq(&hpet_lock);
194 return;
195 }
196
197 timer = devp->hd_timer;
198
199 /* we prefer level triggered mode */
200 v = readl(&timer->hpet_config);
201 if (!(v & Tn_INT_TYPE_CNF_MASK)) {
202 v |= Tn_INT_TYPE_CNF_MASK;
203 writel(v, &timer->hpet_config);
204 }
205 spin_unlock_irq(&hpet_lock);
206
207 v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >>
208 Tn_INT_ROUTE_CAP_SHIFT;
209
210 /*
211 * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by
212 * legacy device. In IO APIC mode, we skip all the legacy IRQS.
213 */
214 if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
215 v &= ~0xf3df;
216 else
217 v &= ~0xffff;
218
219 for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
220 irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
221
222 if (irq >= NR_IRQS) {
223 irq = HPET_MAX_IRQ;
224 break;
225 }
226
227 gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
228 ACPI_ACTIVE_LOW);
229 if (gsi > 0)
230 break;
231
232 /* FIXME: Setup interrupt source table */
233 }
234
235 if (irq < HPET_MAX_IRQ) {
236 spin_lock_irq(&hpet_lock);
237 v = readl(&timer->hpet_config);
238 v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
239 writel(v, &timer->hpet_config);
240 devp->hd_hdwirq = gsi;
241 spin_unlock_irq(&hpet_lock);
242 }
243 return;
244}
245
188static int hpet_open(struct inode *inode, struct file *file) 246static int hpet_open(struct inode *inode, struct file *file)
189{ 247{
190 struct hpet_dev *devp; 248 struct hpet_dev *devp;
@@ -199,8 +257,7 @@ static int hpet_open(struct inode *inode, struct file *file)
199 257
200 for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) 258 for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
201 for (i = 0; i < hpetp->hp_ntimer; i++) 259 for (i = 0; i < hpetp->hp_ntimer; i++)
202 if (hpetp->hp_dev[i].hd_flags & HPET_OPEN 260 if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
203 || hpetp->hp_dev[i].hd_task)
204 continue; 261 continue;
205 else { 262 else {
206 devp = &hpetp->hp_dev[i]; 263 devp = &hpetp->hp_dev[i];
@@ -219,6 +276,8 @@ static int hpet_open(struct inode *inode, struct file *file)
219 spin_unlock_irq(&hpet_lock); 276 spin_unlock_irq(&hpet_lock);
220 unlock_kernel(); 277 unlock_kernel();
221 278
279 hpet_timer_set_irq(devp);
280
222 return 0; 281 return 0;
223} 282}
224 283
@@ -441,7 +500,11 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
441 devp->hd_irq = irq; 500 devp->hd_irq = irq;
442 t = devp->hd_ireqfreq; 501 t = devp->hd_ireqfreq;
443 v = readq(&timer->hpet_config); 502 v = readq(&timer->hpet_config);
444 g = v | Tn_INT_ENB_CNF_MASK; 503
504 /* 64-bit comparators are not yet supported through the ioctls,
505 * so force this into 32-bit mode if it supports both modes
506 */
507 g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK;
445 508
446 if (devp->hd_flags & HPET_PERIODIC) { 509 if (devp->hd_flags & HPET_PERIODIC) {
447 write_counter(t, &timer->hpet_compare); 510 write_counter(t, &timer->hpet_compare);
@@ -451,6 +514,12 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
451 v |= Tn_VAL_SET_CNF_MASK; 514 v |= Tn_VAL_SET_CNF_MASK;
452 writeq(v, &timer->hpet_config); 515 writeq(v, &timer->hpet_config);
453 local_irq_save(flags); 516 local_irq_save(flags);
517
518 /* NOTE: what we modify here is a hidden accumulator
519 * register supported by periodic-capable comparators.
520 * We never want to modify the (single) counter; that
521 * would affect all the comparators.
522 */
454 m = read_counter(&hpet->hpet_mc); 523 m = read_counter(&hpet->hpet_mc);
455 write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); 524 write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
456 } else { 525 } else {
@@ -604,57 +673,6 @@ static int hpet_is_known(struct hpet_data *hdp)
604 return 0; 673 return 0;
605} 674}
606 675
607static inline int hpet_tpcheck(struct hpet_task *tp)
608{
609 struct hpet_dev *devp;
610 struct hpets *hpetp;
611
612 devp = tp->ht_opaque;
613
614 if (!devp)
615 return -ENXIO;
616
617 for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
618 if (devp >= hpetp->hp_dev
619 && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
620 && devp->hd_hpet == hpetp->hp_hpet)
621 return 0;
622
623 return -ENXIO;
624}
625
626#if 0
627int hpet_unregister(struct hpet_task *tp)
628{
629 struct hpet_dev *devp;
630 struct hpet_timer __iomem *timer;
631 int err;
632
633 if ((err = hpet_tpcheck(tp)))
634 return err;
635
636 spin_lock_irq(&hpet_task_lock);
637 spin_lock(&hpet_lock);
638
639 devp = tp->ht_opaque;
640 if (devp->hd_task != tp) {
641 spin_unlock(&hpet_lock);
642 spin_unlock_irq(&hpet_task_lock);
643 return -ENXIO;
644 }
645
646 timer = devp->hd_timer;
647 writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
648 &timer->hpet_config);
649 devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
650 devp->hd_task = NULL;
651 spin_unlock(&hpet_lock);
652 spin_unlock_irq(&hpet_task_lock);
653
654 return 0;
655}
656#endif /* 0 */
657
658static ctl_table hpet_table[] = { 676static ctl_table hpet_table[] = {
659 { 677 {
660 .ctl_name = CTL_UNNUMBERED, 678 .ctl_name = CTL_UNNUMBERED,
@@ -746,6 +764,7 @@ int hpet_alloc(struct hpet_data *hdp)
746 static struct hpets *last = NULL; 764 static struct hpets *last = NULL;
747 unsigned long period; 765 unsigned long period;
748 unsigned long long temp; 766 unsigned long long temp;
767 u32 remainder;
749 768
750 /* 769 /*
751 * hpet_alloc can be called by platform dependent code. 770 * hpet_alloc can be called by platform dependent code.
@@ -809,9 +828,13 @@ int hpet_alloc(struct hpet_data *hdp)
809 printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); 828 printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
810 printk("\n"); 829 printk("\n");
811 830
812 printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n", 831 temp = hpetp->hp_tick_freq;
813 hpetp->hp_which, hpetp->hp_ntimer, 832 remainder = do_div(temp, 1000000);
814 cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq); 833 printk(KERN_INFO
834 "hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n",
835 hpetp->hp_which, hpetp->hp_ntimer,
836 cap & HPET_COUNTER_SIZE_MASK ? 64 : 32,
837 (unsigned) temp, remainder);
815 838
816 mcfg = readq(&hpet->hpet_config); 839 mcfg = readq(&hpet->hpet_config);
817 if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { 840 if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
@@ -874,8 +897,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
874 hdp->hd_address = ioremap(addr.minimum, addr.address_length); 897 hdp->hd_address = ioremap(addr.minimum, addr.address_length);
875 898
876 if (hpet_is_known(hdp)) { 899 if (hpet_is_known(hdp)) {
877 printk(KERN_DEBUG "%s: 0x%lx is busy\n",
878 __func__, hdp->hd_phys_address);
879 iounmap(hdp->hd_address); 900 iounmap(hdp->hd_address);
880 return AE_ALREADY_EXISTS; 901 return AE_ALREADY_EXISTS;
881 } 902 }
@@ -891,8 +912,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
891 HPET_RANGE_SIZE); 912 HPET_RANGE_SIZE);
892 913
893 if (hpet_is_known(hdp)) { 914 if (hpet_is_known(hdp)) {
894 printk(KERN_DEBUG "%s: 0x%lx is busy\n",
895 __func__, hdp->hd_phys_address);
896 iounmap(hdp->hd_address); 915 iounmap(hdp->hd_address);
897 return AE_ALREADY_EXISTS; 916 return AE_ALREADY_EXISTS;
898 } 917 }