diff options
Diffstat (limited to 'drivers/char/hpet.c')
-rw-r--r-- | drivers/char/hpet.c | 90 |
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. */ |
88 | static DEFINE_SPINLOCK(hpet_lock); | 93 | static DEFINE_SPINLOCK(hpet_lock); |
89 | /* A lock for concurrent intermodule access to hpet and isr hpet activity. */ | ||
90 | static 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 | ||
670 | static 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 | ||
690 | int 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 | |||
721 | static ctl_table hpet_table[] = { | 676 | static 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) { |