0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/types.h>
0013 #include <linux/kernel.h>
0014 #include <linux/ioctl.h>
0015 #include <linux/module.h>
0016 #include <linux/init.h>
0017 #include <linux/errno.h>
0018 #include <linux/mm.h>
0019 #include <linux/fs.h>
0020 #include <linux/mmtimer.h>
0021 #include <linux/miscdevice.h>
0022 #include <linux/posix-timers.h>
0023 #include <linux/interrupt.h>
0024 #include <linux/time.h>
0025 #include <linux/math64.h>
0026
0027 #include <asm/genapic.h>
0028 #include <asm/uv/uv_hub.h>
0029 #include <asm/uv/bios.h>
0030 #include <asm/uv/uv.h>
0031
0032 MODULE_AUTHOR("Dimitri Sivanich <sivanich@sgi.com>");
0033 MODULE_DESCRIPTION("SGI UV Memory Mapped RTC Timer");
0034 MODULE_LICENSE("GPL");
0035
0036
0037 #define UV_MMTIMER_NAME "mmtimer"
0038 #define UV_MMTIMER_DESC "SGI UV Memory Mapped RTC Timer"
0039 #define UV_MMTIMER_VERSION "1.0"
0040
0041 static long uv_mmtimer_ioctl(struct file *file, unsigned int cmd,
0042 unsigned long arg);
0043 static int uv_mmtimer_mmap(struct file *file, struct vm_area_struct *vma);
0044
0045
0046
0047
0048 static unsigned long uv_mmtimer_femtoperiod;
0049
0050 static const struct file_operations uv_mmtimer_fops = {
0051 .owner = THIS_MODULE,
0052 .mmap = uv_mmtimer_mmap,
0053 .unlocked_ioctl = uv_mmtimer_ioctl,
0054 .llseek = noop_llseek,
0055 };
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 static long uv_mmtimer_ioctl(struct file *file, unsigned int cmd,
0085 unsigned long arg)
0086 {
0087 int ret = 0;
0088
0089 switch (cmd) {
0090 case MMTIMER_GETOFFSET:
0091
0092
0093
0094
0095
0096
0097
0098 if (uv_get_min_hub_revision_id() == 1)
0099 ret = 0;
0100 else
0101 ret = ((uv_blade_processor_id() * L1_CACHE_BYTES) %
0102 PAGE_SIZE) / 8;
0103 break;
0104
0105 case MMTIMER_GETRES:
0106 if (copy_to_user((unsigned long __user *)arg,
0107 &uv_mmtimer_femtoperiod, sizeof(unsigned long)))
0108 ret = -EFAULT;
0109 break;
0110
0111 case MMTIMER_GETFREQ:
0112 if (copy_to_user((unsigned long __user *)arg,
0113 &sn_rtc_cycles_per_second,
0114 sizeof(unsigned long)))
0115 ret = -EFAULT;
0116 break;
0117
0118 case MMTIMER_GETBITS:
0119 ret = hweight64(UVH_RTC_REAL_TIME_CLOCK_MASK);
0120 break;
0121
0122 case MMTIMER_MMAPAVAIL:
0123 ret = 1;
0124 break;
0125
0126 case MMTIMER_GETCOUNTER:
0127 if (copy_to_user((unsigned long __user *)arg,
0128 (unsigned long *)uv_local_mmr_address(UVH_RTC),
0129 sizeof(unsigned long)))
0130 ret = -EFAULT;
0131 break;
0132 default:
0133 ret = -ENOTTY;
0134 break;
0135 }
0136 return ret;
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147 static int uv_mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
0148 {
0149 unsigned long uv_mmtimer_addr;
0150
0151 if (vma->vm_end - vma->vm_start != PAGE_SIZE)
0152 return -EINVAL;
0153
0154 if (vma->vm_flags & VM_WRITE)
0155 return -EPERM;
0156
0157 if (PAGE_SIZE > (1 << 16))
0158 return -ENOSYS;
0159
0160 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
0161
0162 uv_mmtimer_addr = UV_LOCAL_MMR_BASE | UVH_RTC;
0163 uv_mmtimer_addr &= ~(PAGE_SIZE - 1);
0164 uv_mmtimer_addr &= 0xfffffffffffffffUL;
0165
0166 if (remap_pfn_range(vma, vma->vm_start, uv_mmtimer_addr >> PAGE_SHIFT,
0167 PAGE_SIZE, vma->vm_page_prot)) {
0168 printk(KERN_ERR "remap_pfn_range failed in uv_mmtimer_mmap\n");
0169 return -EAGAIN;
0170 }
0171
0172 return 0;
0173 }
0174
0175 static struct miscdevice uv_mmtimer_miscdev = {
0176 MISC_DYNAMIC_MINOR,
0177 UV_MMTIMER_NAME,
0178 &uv_mmtimer_fops
0179 };
0180
0181
0182
0183
0184
0185
0186
0187 static int __init uv_mmtimer_init(void)
0188 {
0189 if (!is_uv_system()) {
0190 printk(KERN_ERR "%s: Hardware unsupported\n", UV_MMTIMER_NAME);
0191 return -1;
0192 }
0193
0194
0195
0196
0197 if (sn_rtc_cycles_per_second < 100000) {
0198 printk(KERN_ERR "%s: unable to determine clock frequency\n",
0199 UV_MMTIMER_NAME);
0200 return -1;
0201 }
0202
0203 uv_mmtimer_femtoperiod = ((unsigned long)1E15 +
0204 sn_rtc_cycles_per_second / 2) /
0205 sn_rtc_cycles_per_second;
0206
0207 if (misc_register(&uv_mmtimer_miscdev)) {
0208 printk(KERN_ERR "%s: failed to register device\n",
0209 UV_MMTIMER_NAME);
0210 return -1;
0211 }
0212
0213 printk(KERN_INFO "%s: v%s, %ld MHz\n", UV_MMTIMER_DESC,
0214 UV_MMTIMER_VERSION,
0215 sn_rtc_cycles_per_second/(unsigned long)1E6);
0216
0217 return 0;
0218 }
0219
0220 module_init(uv_mmtimer_init);