aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hpet.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/hpet.c')
-rw-r--r--drivers/char/hpet.c90
1 files changed, 24 insertions, 66 deletions
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index f3981ffe20f0..4bc1da4d4f80 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);
@@ -260,8 +257,7 @@ static int hpet_open(struct inode *inode, struct file *file)
260 257
261 for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) 258 for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
262 for (i = 0; i < hpetp->hp_ntimer; i++) 259 for (i = 0; i < hpetp->hp_ntimer; i++)
263 if (hpetp->hp_dev[i].hd_flags & HPET_OPEN 260 if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
264 || hpetp->hp_dev[i].hd_task)
265 continue; 261 continue;
266 else { 262 else {
267 devp = &hpetp->hp_dev[i]; 263 devp = &hpetp->hp_dev[i];
@@ -504,7 +500,11 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
504 devp->hd_irq = irq; 500 devp->hd_irq = irq;
505 t = devp->hd_ireqfreq; 501 t = devp->hd_ireqfreq;
506 v = readq(&timer->hpet_config); 502 v = readq(&timer->hpet_config);
507 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;
508 508
509 if (devp->hd_flags & HPET_PERIODIC) { 509 if (devp->hd_flags & HPET_PERIODIC) {
510 write_counter(t, &timer->hpet_compare); 510 write_counter(t, &timer->hpet_compare);
@@ -514,6 +514,12 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
514 v |= Tn_VAL_SET_CNF_MASK; 514 v |= Tn_VAL_SET_CNF_MASK;
515 writeq(v, &timer->hpet_config); 515 writeq(v, &timer->hpet_config);
516 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 */
517 m = read_counter(&hpet->hpet_mc); 523 m = read_counter(&hpet->hpet_mc);
518 write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); 524 write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
519 } else { 525 } else {
@@ -667,57 +673,6 @@ static int hpet_is_known(struct hpet_data *hdp)
667 return 0; 673 return 0;
668} 674}
669 675
670static inline int hpet_tpcheck(struct hpet_task *tp)
671{
672 struct hpet_dev *devp;
673 struct hpets *hpetp;
674
675 devp = tp->ht_opaque;
676
677 if (!devp)
678 return -ENXIO;
679
680 for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
681 if (devp >= hpetp->hp_dev
682 && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
683 && devp->hd_hpet == hpetp->hp_hpet)
684 return 0;
685
686 return -ENXIO;
687}
688
689#if 0
690int hpet_unregister(struct hpet_task *tp)
691{
692 struct hpet_dev *devp;
693 struct hpet_timer __iomem *timer;
694 int err;
695
696 if ((err = hpet_tpcheck(tp)))
697 return err;
698
699 spin_lock_irq(&hpet_task_lock);
700 spin_lock(&hpet_lock);
701
702 devp = tp->ht_opaque;
703 if (devp->hd_task != tp) {
704 spin_unlock(&hpet_lock);
705 spin_unlock_irq(&hpet_task_lock);
706 return -ENXIO;
707 }
708
709 timer = devp->hd_timer;
710 writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
711 &timer->hpet_config);
712 devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
713 devp->hd_task = NULL;
714 spin_unlock(&hpet_lock);
715 spin_unlock_irq(&hpet_task_lock);
716
717 return 0;
718}
719#endif /* 0 */
720
721static ctl_table hpet_table[] = { 676static ctl_table hpet_table[] = {
722 { 677 {
723 .ctl_name = CTL_UNNUMBERED, 678 .ctl_name = CTL_UNNUMBERED,
@@ -872,9 +827,12 @@ int hpet_alloc(struct hpet_data *hdp)
872 printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); 827 printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
873 printk("\n"); 828 printk("\n");
874 829
875 printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n", 830 printk(KERN_INFO
876 hpetp->hp_which, hpetp->hp_ntimer, 831 "hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n",
877 cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq); 832 hpetp->hp_which, hpetp->hp_ntimer,
833 cap & HPET_COUNTER_SIZE_MASK ? 64 : 32,
834 (unsigned) (hpetp->hp_tick_freq / 1000000),
835 (unsigned) (hpetp->hp_tick_freq % 1000000));
878 836
879 mcfg = readq(&hpet->hpet_config); 837 mcfg = readq(&hpet->hpet_config);
880 if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { 838 if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {