aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hpet.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2010-10-30 04:43:08 -0400
committerIngo Molnar <mingo@elte.hu>2010-10-30 04:43:08 -0400
commit169ed55bd30305b933f52bfab32a58671d44ab68 (patch)
tree32e280957474f458901abfce16fa2a1687ef7497 /drivers/char/hpet.c
parent3d7851b3cdd43a734e5cc4c643fd886ab28ad4d5 (diff)
parent45f81b1c96d9793e47ce925d257ea693ce0b193e (diff)
Merge branch 'tip/perf/jump-label-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into perf/urgent
Diffstat (limited to 'drivers/char/hpet.c')
-rw-r--r--drivers/char/hpet.c136
1 files changed, 91 insertions, 45 deletions
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index a0a1829d3198..55b8667f739f 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -30,13 +30,14 @@
30#include <linux/bcd.h> 30#include <linux/bcd.h>
31#include <linux/seq_file.h> 31#include <linux/seq_file.h>
32#include <linux/bitops.h> 32#include <linux/bitops.h>
33#include <linux/compat.h>
33#include <linux/clocksource.h> 34#include <linux/clocksource.h>
35#include <linux/uaccess.h>
34#include <linux/slab.h> 36#include <linux/slab.h>
37#include <linux/io.h>
35 38
36#include <asm/current.h> 39#include <asm/current.h>
37#include <asm/uaccess.h>
38#include <asm/system.h> 40#include <asm/system.h>
39#include <asm/io.h>
40#include <asm/irq.h> 41#include <asm/irq.h>
41#include <asm/div64.h> 42#include <asm/div64.h>
42 43
@@ -67,6 +68,7 @@
67#define read_counter(MC) readl(MC) 68#define read_counter(MC) readl(MC)
68#endif 69#endif
69 70
71static DEFINE_MUTEX(hpet_mutex); /* replaces BKL */
70static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; 72static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
71 73
72/* This clocksource driver currently only works on ia64 */ 74/* This clocksource driver currently only works on ia64 */
@@ -79,13 +81,13 @@ static cycle_t read_hpet(struct clocksource *cs)
79} 81}
80 82
81static struct clocksource clocksource_hpet = { 83static struct clocksource clocksource_hpet = {
82 .name = "hpet", 84 .name = "hpet",
83 .rating = 250, 85 .rating = 250,
84 .read = read_hpet, 86 .read = read_hpet,
85 .mask = CLOCKSOURCE_MASK(64), 87 .mask = CLOCKSOURCE_MASK(64),
86 .mult = 0, /* to be calculated */ 88 .mult = 0, /* to be calculated */
87 .shift = 10, 89 .shift = 10,
88 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 90 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
89}; 91};
90static struct clocksource *hpet_clocksource; 92static struct clocksource *hpet_clocksource;
91#endif 93#endif
@@ -250,7 +252,7 @@ static int hpet_open(struct inode *inode, struct file *file)
250 if (file->f_mode & FMODE_WRITE) 252 if (file->f_mode & FMODE_WRITE)
251 return -EINVAL; 253 return -EINVAL;
252 254
253 lock_kernel(); 255 mutex_lock(&hpet_mutex);
254 spin_lock_irq(&hpet_lock); 256 spin_lock_irq(&hpet_lock);
255 257
256 for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) 258 for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
@@ -264,7 +266,7 @@ static int hpet_open(struct inode *inode, struct file *file)
264 266
265 if (!devp) { 267 if (!devp) {
266 spin_unlock_irq(&hpet_lock); 268 spin_unlock_irq(&hpet_lock);
267 unlock_kernel(); 269 mutex_unlock(&hpet_mutex);
268 return -EBUSY; 270 return -EBUSY;
269 } 271 }
270 272
@@ -272,7 +274,7 @@ static int hpet_open(struct inode *inode, struct file *file)
272 devp->hd_irqdata = 0; 274 devp->hd_irqdata = 0;
273 devp->hd_flags |= HPET_OPEN; 275 devp->hd_flags |= HPET_OPEN;
274 spin_unlock_irq(&hpet_lock); 276 spin_unlock_irq(&hpet_lock);
275 unlock_kernel(); 277 mutex_unlock(&hpet_mutex);
276 278
277 hpet_timer_set_irq(devp); 279 hpet_timer_set_irq(devp);
278 280
@@ -429,22 +431,6 @@ static int hpet_release(struct inode *inode, struct file *file)
429 return 0; 431 return 0;
430} 432}
431 433
432static int hpet_ioctl_common(struct hpet_dev *, int, unsigned long, int);
433
434static long hpet_ioctl(struct file *file, unsigned int cmd,
435 unsigned long arg)
436{
437 struct hpet_dev *devp;
438 int ret;
439
440 devp = file->private_data;
441 lock_kernel();
442 ret = hpet_ioctl_common(devp, cmd, arg, 0);
443 unlock_kernel();
444
445 return ret;
446}
447
448static int hpet_ioctl_ieon(struct hpet_dev *devp) 434static int hpet_ioctl_ieon(struct hpet_dev *devp)
449{ 435{
450 struct hpet_timer __iomem *timer; 436 struct hpet_timer __iomem *timer;
@@ -479,6 +465,21 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
479 if (irq) { 465 if (irq) {
480 unsigned long irq_flags; 466 unsigned long irq_flags;
481 467
468 if (devp->hd_flags & HPET_SHARED_IRQ) {
469 /*
470 * To prevent the interrupt handler from seeing an
471 * unwanted interrupt status bit, program the timer
472 * so that it will not fire in the near future ...
473 */
474 writel(readl(&timer->hpet_config) & ~Tn_TYPE_CNF_MASK,
475 &timer->hpet_config);
476 write_counter(read_counter(&hpet->hpet_mc),
477 &timer->hpet_compare);
478 /* ... and clear any left-over status. */
479 isr = 1 << (devp - devp->hd_hpets->hp_dev);
480 writel(isr, &hpet->hpet_isr);
481 }
482
482 sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); 483 sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
483 irq_flags = devp->hd_flags & HPET_SHARED_IRQ 484 irq_flags = devp->hd_flags & HPET_SHARED_IRQ
484 ? IRQF_SHARED : IRQF_DISABLED; 485 ? IRQF_SHARED : IRQF_DISABLED;
@@ -553,7 +554,8 @@ static inline unsigned long hpet_time_div(struct hpets *hpets,
553} 554}
554 555
555static int 556static int
556hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) 557hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
558 struct hpet_info *info)
557{ 559{
558 struct hpet_timer __iomem *timer; 560 struct hpet_timer __iomem *timer;
559 struct hpet __iomem *hpet; 561 struct hpet __iomem *hpet;
@@ -594,23 +596,14 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
594 break; 596 break;
595 case HPET_INFO: 597 case HPET_INFO:
596 { 598 {
597 struct hpet_info info; 599 memset(info, 0, sizeof(*info));
598
599 if (devp->hd_ireqfreq) 600 if (devp->hd_ireqfreq)
600 info.hi_ireqfreq = 601 info->hi_ireqfreq =
601 hpet_time_div(hpetp, devp->hd_ireqfreq); 602 hpet_time_div(hpetp, devp->hd_ireqfreq);
602 else 603 info->hi_flags =
603 info.hi_ireqfreq = 0;
604 info.hi_flags =
605 readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK; 604 readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
606 info.hi_hpet = hpetp->hp_which; 605 info->hi_hpet = hpetp->hp_which;
607 info.hi_timer = devp - hpetp->hp_dev; 606 info->hi_timer = devp - hpetp->hp_dev;
608 if (kernel)
609 memcpy((void *)arg, &info, sizeof(info));
610 else
611 if (copy_to_user((void __user *)arg, &info,
612 sizeof(info)))
613 err = -EFAULT;
614 break; 607 break;
615 } 608 }
616 case HPET_EPI: 609 case HPET_EPI:
@@ -636,7 +629,7 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
636 devp->hd_flags &= ~HPET_PERIODIC; 629 devp->hd_flags &= ~HPET_PERIODIC;
637 break; 630 break;
638 case HPET_IRQFREQ: 631 case HPET_IRQFREQ:
639 if (!kernel && (arg > hpet_max_freq) && 632 if ((arg > hpet_max_freq) &&
640 !capable(CAP_SYS_RESOURCE)) { 633 !capable(CAP_SYS_RESOURCE)) {
641 err = -EACCES; 634 err = -EACCES;
642 break; 635 break;
@@ -653,12 +646,63 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
653 return err; 646 return err;
654} 647}
655 648
649static long
650hpet_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
651{
652 struct hpet_info info;
653 int err;
654
655 mutex_lock(&hpet_mutex);
656 err = hpet_ioctl_common(file->private_data, cmd, arg, &info);
657 mutex_unlock(&hpet_mutex);
658
659 if ((cmd == HPET_INFO) && !err &&
660 (copy_to_user((void __user *)arg, &info, sizeof(info))))
661 err = -EFAULT;
662
663 return err;
664}
665
666#ifdef CONFIG_COMPAT
667struct compat_hpet_info {
668 compat_ulong_t hi_ireqfreq; /* Hz */
669 compat_ulong_t hi_flags; /* information */
670 unsigned short hi_hpet;
671 unsigned short hi_timer;
672};
673
674static long
675hpet_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
676{
677 struct hpet_info info;
678 int err;
679
680 mutex_lock(&hpet_mutex);
681 err = hpet_ioctl_common(file->private_data, cmd, arg, &info);
682 mutex_unlock(&hpet_mutex);
683
684 if ((cmd == HPET_INFO) && !err) {
685 struct compat_hpet_info __user *u = compat_ptr(arg);
686 if (put_user(info.hi_ireqfreq, &u->hi_ireqfreq) ||
687 put_user(info.hi_flags, &u->hi_flags) ||
688 put_user(info.hi_hpet, &u->hi_hpet) ||
689 put_user(info.hi_timer, &u->hi_timer))
690 err = -EFAULT;
691 }
692
693 return err;
694}
695#endif
696
656static const struct file_operations hpet_fops = { 697static const struct file_operations hpet_fops = {
657 .owner = THIS_MODULE, 698 .owner = THIS_MODULE,
658 .llseek = no_llseek, 699 .llseek = no_llseek,
659 .read = hpet_read, 700 .read = hpet_read,
660 .poll = hpet_poll, 701 .poll = hpet_poll,
661 .unlocked_ioctl = hpet_ioctl, 702 .unlocked_ioctl = hpet_ioctl,
703#ifdef CONFIG_COMPAT
704 .compat_ioctl = hpet_compat_ioctl,
705#endif
662 .open = hpet_open, 706 .open = hpet_open,
663 .release = hpet_release, 707 .release = hpet_release,
664 .fasync = hpet_fasync, 708 .fasync = hpet_fasync,
@@ -781,7 +825,7 @@ int hpet_alloc(struct hpet_data *hdp)
781 struct hpets *hpetp; 825 struct hpets *hpetp;
782 size_t siz; 826 size_t siz;
783 struct hpet __iomem *hpet; 827 struct hpet __iomem *hpet;
784 static struct hpets *last = NULL; 828 static struct hpets *last;
785 unsigned long period; 829 unsigned long period;
786 unsigned long long temp; 830 unsigned long long temp;
787 u32 remainder; 831 u32 remainder;
@@ -970,6 +1014,8 @@ static int hpet_acpi_add(struct acpi_device *device)
970 return -ENODEV; 1014 return -ENODEV;
971 1015
972 if (!data.hd_address || !data.hd_nirqs) { 1016 if (!data.hd_address || !data.hd_nirqs) {
1017 if (data.hd_address)
1018 iounmap(data.hd_address);
973 printk("%s: no address or irqs in _CRS\n", __func__); 1019 printk("%s: no address or irqs in _CRS\n", __func__);
974 return -ENODEV; 1020 return -ENODEV;
975 } 1021 }