1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Intel & MS High Precision Event Timer Implementation. |
4 | * |
5 | * Copyright (C) 2003 Intel Corporation |
6 | * Venki Pallipadi |
7 | * (c) Copyright 2004 Hewlett-Packard Development Company, L.P. |
8 | * Bob Picco <robert.picco@hp.com> |
9 | */ |
10 | |
11 | #include <linux/interrupt.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/types.h> |
14 | #include <linux/miscdevice.h> |
15 | #include <linux/major.h> |
16 | #include <linux/ioport.h> |
17 | #include <linux/fcntl.h> |
18 | #include <linux/init.h> |
19 | #include <linux/io-64-nonatomic-lo-hi.h> |
20 | #include <linux/poll.h> |
21 | #include <linux/mm.h> |
22 | #include <linux/proc_fs.h> |
23 | #include <linux/spinlock.h> |
24 | #include <linux/sysctl.h> |
25 | #include <linux/wait.h> |
26 | #include <linux/sched/signal.h> |
27 | #include <linux/bcd.h> |
28 | #include <linux/seq_file.h> |
29 | #include <linux/bitops.h> |
30 | #include <linux/compat.h> |
31 | #include <linux/clocksource.h> |
32 | #include <linux/uaccess.h> |
33 | #include <linux/slab.h> |
34 | #include <linux/io.h> |
35 | #include <linux/acpi.h> |
36 | #include <linux/hpet.h> |
37 | #include <asm/current.h> |
38 | #include <asm/irq.h> |
39 | #include <asm/div64.h> |
40 | |
41 | /* |
42 | * The High Precision Event Timer driver. |
43 | * This driver is closely modelled after the rtc.c driver. |
44 | * See HPET spec revision 1. |
45 | */ |
46 | #define HPET_USER_FREQ (64) |
47 | #define HPET_DRIFT (500) |
48 | |
49 | #define HPET_RANGE_SIZE 1024 /* from HPET spec */ |
50 | |
51 | |
52 | /* WARNING -- don't get confused. These macros are never used |
53 | * to write the (single) counter, and rarely to read it. |
54 | * They're badly named; to fix, someday. |
55 | */ |
56 | #if BITS_PER_LONG == 64 |
57 | #define write_counter(V, MC) writeq(V, MC) |
58 | #define read_counter(MC) readq(MC) |
59 | #else |
60 | #define write_counter(V, MC) writel(V, MC) |
61 | #define read_counter(MC) readl(MC) |
62 | #endif |
63 | |
64 | static DEFINE_MUTEX(hpet_mutex); /* replaces BKL */ |
65 | static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; |
66 | |
67 | /* A lock for concurrent access by app and isr hpet activity. */ |
68 | static DEFINE_SPINLOCK(hpet_lock); |
69 | |
70 | #define HPET_DEV_NAME (7) |
71 | |
72 | struct hpet_dev { |
73 | struct hpets *hd_hpets; |
74 | struct hpet __iomem *hd_hpet; |
75 | struct hpet_timer __iomem *hd_timer; |
76 | unsigned long hd_ireqfreq; |
77 | unsigned long hd_irqdata; |
78 | wait_queue_head_t hd_waitqueue; |
79 | struct fasync_struct *hd_async_queue; |
80 | unsigned int hd_flags; |
81 | unsigned int hd_irq; |
82 | unsigned int hd_hdwirq; |
83 | char hd_name[HPET_DEV_NAME]; |
84 | }; |
85 | |
86 | struct hpets { |
87 | struct hpets *hp_next; |
88 | struct hpet __iomem *hp_hpet; |
89 | unsigned long hp_hpet_phys; |
90 | unsigned long long hp_tick_freq; |
91 | unsigned long hp_delta; |
92 | unsigned int hp_ntimer; |
93 | unsigned int hp_which; |
94 | struct hpet_dev hp_dev[] __counted_by(hp_ntimer); |
95 | }; |
96 | |
97 | static struct hpets *hpets; |
98 | |
99 | #define HPET_OPEN 0x0001 |
100 | #define HPET_IE 0x0002 /* interrupt enabled */ |
101 | #define HPET_PERIODIC 0x0004 |
102 | #define HPET_SHARED_IRQ 0x0008 |
103 | |
104 | static irqreturn_t hpet_interrupt(int irq, void *data) |
105 | { |
106 | struct hpet_dev *devp; |
107 | unsigned long isr; |
108 | |
109 | devp = data; |
110 | isr = 1 << (devp - devp->hd_hpets->hp_dev); |
111 | |
112 | if ((devp->hd_flags & HPET_SHARED_IRQ) && |
113 | !(isr & readl(addr: &devp->hd_hpet->hpet_isr))) |
114 | return IRQ_NONE; |
115 | |
116 | spin_lock(lock: &hpet_lock); |
117 | devp->hd_irqdata++; |
118 | |
119 | /* |
120 | * For non-periodic timers, increment the accumulator. |
121 | * This has the effect of treating non-periodic like periodic. |
122 | */ |
123 | if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) { |
124 | unsigned long t, mc, base, k; |
125 | struct hpet __iomem *hpet = devp->hd_hpet; |
126 | struct hpets *hpetp = devp->hd_hpets; |
127 | |
128 | t = devp->hd_ireqfreq; |
129 | read_counter(&devp->hd_timer->hpet_compare); |
130 | mc = read_counter(&hpet->hpet_mc); |
131 | /* The time for the next interrupt would logically be t + m, |
132 | * however, if we are very unlucky and the interrupt is delayed |
133 | * for longer than t then we will completely miss the next |
134 | * interrupt if we set t + m and an application will hang. |
135 | * Therefore we need to make a more complex computation assuming |
136 | * that there exists a k for which the following is true: |
137 | * k * t + base < mc + delta |
138 | * (k + 1) * t + base > mc + delta |
139 | * where t is the interval in hpet ticks for the given freq, |
140 | * base is the theoretical start value 0 < base < t, |
141 | * mc is the main counter value at the time of the interrupt, |
142 | * delta is the time it takes to write the a value to the |
143 | * comparator. |
144 | * k may then be computed as (mc - base + delta) / t . |
145 | */ |
146 | base = mc % t; |
147 | k = (mc - base + hpetp->hp_delta) / t; |
148 | write_counter(t * (k + 1) + base, |
149 | &devp->hd_timer->hpet_compare); |
150 | } |
151 | |
152 | if (devp->hd_flags & HPET_SHARED_IRQ) |
153 | writel(val: isr, addr: &devp->hd_hpet->hpet_isr); |
154 | spin_unlock(lock: &hpet_lock); |
155 | |
156 | wake_up_interruptible(&devp->hd_waitqueue); |
157 | |
158 | kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN); |
159 | |
160 | return IRQ_HANDLED; |
161 | } |
162 | |
163 | static void hpet_timer_set_irq(struct hpet_dev *devp) |
164 | { |
165 | unsigned long v; |
166 | int irq, gsi; |
167 | struct hpet_timer __iomem *timer; |
168 | |
169 | spin_lock_irq(lock: &hpet_lock); |
170 | if (devp->hd_hdwirq) { |
171 | spin_unlock_irq(lock: &hpet_lock); |
172 | return; |
173 | } |
174 | |
175 | timer = devp->hd_timer; |
176 | |
177 | /* we prefer level triggered mode */ |
178 | v = readl(addr: &timer->hpet_config); |
179 | if (!(v & Tn_INT_TYPE_CNF_MASK)) { |
180 | v |= Tn_INT_TYPE_CNF_MASK; |
181 | writel(val: v, addr: &timer->hpet_config); |
182 | } |
183 | spin_unlock_irq(lock: &hpet_lock); |
184 | |
185 | v = (readq(addr: &timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >> |
186 | Tn_INT_ROUTE_CAP_SHIFT; |
187 | |
188 | /* |
189 | * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by |
190 | * legacy device. In IO APIC mode, we skip all the legacy IRQS. |
191 | */ |
192 | if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) |
193 | v &= ~0xf3df; |
194 | else |
195 | v &= ~0xffff; |
196 | |
197 | for_each_set_bit(irq, &v, HPET_MAX_IRQ) { |
198 | if (irq >= nr_irqs) { |
199 | irq = HPET_MAX_IRQ; |
200 | break; |
201 | } |
202 | |
203 | gsi = acpi_register_gsi(NULL, gsi: irq, ACPI_LEVEL_SENSITIVE, |
204 | ACPI_ACTIVE_LOW); |
205 | if (gsi > 0) |
206 | break; |
207 | |
208 | /* FIXME: Setup interrupt source table */ |
209 | } |
210 | |
211 | if (irq < HPET_MAX_IRQ) { |
212 | spin_lock_irq(lock: &hpet_lock); |
213 | v = readl(addr: &timer->hpet_config); |
214 | v |= irq << Tn_INT_ROUTE_CNF_SHIFT; |
215 | writel(val: v, addr: &timer->hpet_config); |
216 | devp->hd_hdwirq = gsi; |
217 | spin_unlock_irq(lock: &hpet_lock); |
218 | } |
219 | return; |
220 | } |
221 | |
222 | static int hpet_open(struct inode *inode, struct file *file) |
223 | { |
224 | struct hpet_dev *devp; |
225 | struct hpets *hpetp; |
226 | int i; |
227 | |
228 | if (file->f_mode & FMODE_WRITE) |
229 | return -EINVAL; |
230 | |
231 | mutex_lock(&hpet_mutex); |
232 | spin_lock_irq(lock: &hpet_lock); |
233 | |
234 | for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) |
235 | for (i = 0; i < hpetp->hp_ntimer; i++) |
236 | if (hpetp->hp_dev[i].hd_flags & HPET_OPEN) { |
237 | continue; |
238 | } else { |
239 | devp = &hpetp->hp_dev[i]; |
240 | break; |
241 | } |
242 | |
243 | if (!devp) { |
244 | spin_unlock_irq(lock: &hpet_lock); |
245 | mutex_unlock(lock: &hpet_mutex); |
246 | return -EBUSY; |
247 | } |
248 | |
249 | file->private_data = devp; |
250 | devp->hd_irqdata = 0; |
251 | devp->hd_flags |= HPET_OPEN; |
252 | spin_unlock_irq(lock: &hpet_lock); |
253 | mutex_unlock(lock: &hpet_mutex); |
254 | |
255 | hpet_timer_set_irq(devp); |
256 | |
257 | return 0; |
258 | } |
259 | |
260 | static ssize_t |
261 | hpet_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) |
262 | { |
263 | DECLARE_WAITQUEUE(wait, current); |
264 | unsigned long data; |
265 | ssize_t retval; |
266 | struct hpet_dev *devp; |
267 | |
268 | devp = file->private_data; |
269 | if (!devp->hd_ireqfreq) |
270 | return -EIO; |
271 | |
272 | if (count < sizeof(unsigned long)) |
273 | return -EINVAL; |
274 | |
275 | add_wait_queue(wq_head: &devp->hd_waitqueue, wq_entry: &wait); |
276 | |
277 | for ( ; ; ) { |
278 | set_current_state(TASK_INTERRUPTIBLE); |
279 | |
280 | spin_lock_irq(lock: &hpet_lock); |
281 | data = devp->hd_irqdata; |
282 | devp->hd_irqdata = 0; |
283 | spin_unlock_irq(lock: &hpet_lock); |
284 | |
285 | if (data) { |
286 | break; |
287 | } else if (file->f_flags & O_NONBLOCK) { |
288 | retval = -EAGAIN; |
289 | goto out; |
290 | } else if (signal_pending(current)) { |
291 | retval = -ERESTARTSYS; |
292 | goto out; |
293 | } |
294 | schedule(); |
295 | } |
296 | |
297 | retval = put_user(data, (unsigned long __user *)buf); |
298 | if (!retval) |
299 | retval = sizeof(unsigned long); |
300 | out: |
301 | __set_current_state(TASK_RUNNING); |
302 | remove_wait_queue(wq_head: &devp->hd_waitqueue, wq_entry: &wait); |
303 | |
304 | return retval; |
305 | } |
306 | |
307 | static __poll_t hpet_poll(struct file *file, poll_table * wait) |
308 | { |
309 | unsigned long v; |
310 | struct hpet_dev *devp; |
311 | |
312 | devp = file->private_data; |
313 | |
314 | if (!devp->hd_ireqfreq) |
315 | return 0; |
316 | |
317 | poll_wait(filp: file, wait_address: &devp->hd_waitqueue, p: wait); |
318 | |
319 | spin_lock_irq(lock: &hpet_lock); |
320 | v = devp->hd_irqdata; |
321 | spin_unlock_irq(lock: &hpet_lock); |
322 | |
323 | if (v != 0) |
324 | return EPOLLIN | EPOLLRDNORM; |
325 | |
326 | return 0; |
327 | } |
328 | |
329 | #ifdef CONFIG_HPET_MMAP |
330 | #ifdef CONFIG_HPET_MMAP_DEFAULT |
331 | static int hpet_mmap_enabled = 1; |
332 | #else |
333 | static int hpet_mmap_enabled = 0; |
334 | #endif |
335 | |
336 | static __init int hpet_mmap_enable(char *str) |
337 | { |
338 | get_option(str: &str, pint: &hpet_mmap_enabled); |
339 | pr_info("HPET mmap %s\n" , hpet_mmap_enabled ? "enabled" : "disabled" ); |
340 | return 1; |
341 | } |
342 | __setup("hpet_mmap=" , hpet_mmap_enable); |
343 | |
344 | static int hpet_mmap(struct file *file, struct vm_area_struct *vma) |
345 | { |
346 | struct hpet_dev *devp; |
347 | unsigned long addr; |
348 | |
349 | if (!hpet_mmap_enabled) |
350 | return -EACCES; |
351 | |
352 | devp = file->private_data; |
353 | addr = devp->hd_hpets->hp_hpet_phys; |
354 | |
355 | if (addr & (PAGE_SIZE - 1)) |
356 | return -ENOSYS; |
357 | |
358 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
359 | return vm_iomap_memory(vma, start: addr, PAGE_SIZE); |
360 | } |
361 | #else |
362 | static int hpet_mmap(struct file *file, struct vm_area_struct *vma) |
363 | { |
364 | return -ENOSYS; |
365 | } |
366 | #endif |
367 | |
368 | static int hpet_fasync(int fd, struct file *file, int on) |
369 | { |
370 | struct hpet_dev *devp; |
371 | |
372 | devp = file->private_data; |
373 | |
374 | if (fasync_helper(fd, file, on, &devp->hd_async_queue) >= 0) |
375 | return 0; |
376 | else |
377 | return -EIO; |
378 | } |
379 | |
380 | static int hpet_release(struct inode *inode, struct file *file) |
381 | { |
382 | struct hpet_dev *devp; |
383 | struct hpet_timer __iomem *timer; |
384 | int irq = 0; |
385 | |
386 | devp = file->private_data; |
387 | timer = devp->hd_timer; |
388 | |
389 | spin_lock_irq(lock: &hpet_lock); |
390 | |
391 | writeq(val: (readq(addr: &timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK), |
392 | addr: &timer->hpet_config); |
393 | |
394 | irq = devp->hd_irq; |
395 | devp->hd_irq = 0; |
396 | |
397 | devp->hd_ireqfreq = 0; |
398 | |
399 | if (devp->hd_flags & HPET_PERIODIC |
400 | && readq(addr: &timer->hpet_config) & Tn_TYPE_CNF_MASK) { |
401 | unsigned long v; |
402 | |
403 | v = readq(addr: &timer->hpet_config); |
404 | v ^= Tn_TYPE_CNF_MASK; |
405 | writeq(val: v, addr: &timer->hpet_config); |
406 | } |
407 | |
408 | devp->hd_flags &= ~(HPET_OPEN | HPET_IE | HPET_PERIODIC); |
409 | spin_unlock_irq(lock: &hpet_lock); |
410 | |
411 | if (irq) |
412 | free_irq(irq, devp); |
413 | |
414 | file->private_data = NULL; |
415 | return 0; |
416 | } |
417 | |
418 | static int hpet_ioctl_ieon(struct hpet_dev *devp) |
419 | { |
420 | struct hpet_timer __iomem *timer; |
421 | struct hpet __iomem *hpet; |
422 | struct hpets *hpetp; |
423 | int irq; |
424 | unsigned long g, v, t, m; |
425 | unsigned long flags, isr; |
426 | |
427 | timer = devp->hd_timer; |
428 | hpet = devp->hd_hpet; |
429 | hpetp = devp->hd_hpets; |
430 | |
431 | if (!devp->hd_ireqfreq) |
432 | return -EIO; |
433 | |
434 | spin_lock_irq(lock: &hpet_lock); |
435 | |
436 | if (devp->hd_flags & HPET_IE) { |
437 | spin_unlock_irq(lock: &hpet_lock); |
438 | return -EBUSY; |
439 | } |
440 | |
441 | devp->hd_flags |= HPET_IE; |
442 | |
443 | if (readl(addr: &timer->hpet_config) & Tn_INT_TYPE_CNF_MASK) |
444 | devp->hd_flags |= HPET_SHARED_IRQ; |
445 | spin_unlock_irq(lock: &hpet_lock); |
446 | |
447 | irq = devp->hd_hdwirq; |
448 | |
449 | if (irq) { |
450 | unsigned long irq_flags; |
451 | |
452 | if (devp->hd_flags & HPET_SHARED_IRQ) { |
453 | /* |
454 | * To prevent the interrupt handler from seeing an |
455 | * unwanted interrupt status bit, program the timer |
456 | * so that it will not fire in the near future ... |
457 | */ |
458 | writel(readl(addr: &timer->hpet_config) & ~Tn_TYPE_CNF_MASK, |
459 | addr: &timer->hpet_config); |
460 | write_counter(read_counter(&hpet->hpet_mc), |
461 | &timer->hpet_compare); |
462 | /* ... and clear any left-over status. */ |
463 | isr = 1 << (devp - devp->hd_hpets->hp_dev); |
464 | writel(val: isr, addr: &hpet->hpet_isr); |
465 | } |
466 | |
467 | sprintf(buf: devp->hd_name, fmt: "hpet%d" , (int)(devp - hpetp->hp_dev)); |
468 | irq_flags = devp->hd_flags & HPET_SHARED_IRQ ? IRQF_SHARED : 0; |
469 | if (request_irq(irq, handler: hpet_interrupt, flags: irq_flags, |
470 | name: devp->hd_name, dev: (void *)devp)) { |
471 | printk(KERN_ERR "hpet: IRQ %d is not free\n" , irq); |
472 | irq = 0; |
473 | } |
474 | } |
475 | |
476 | if (irq == 0) { |
477 | spin_lock_irq(lock: &hpet_lock); |
478 | devp->hd_flags ^= HPET_IE; |
479 | spin_unlock_irq(lock: &hpet_lock); |
480 | return -EIO; |
481 | } |
482 | |
483 | devp->hd_irq = irq; |
484 | t = devp->hd_ireqfreq; |
485 | v = readq(addr: &timer->hpet_config); |
486 | |
487 | /* 64-bit comparators are not yet supported through the ioctls, |
488 | * so force this into 32-bit mode if it supports both modes |
489 | */ |
490 | g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK; |
491 | |
492 | if (devp->hd_flags & HPET_PERIODIC) { |
493 | g |= Tn_TYPE_CNF_MASK; |
494 | v |= Tn_TYPE_CNF_MASK | Tn_VAL_SET_CNF_MASK; |
495 | writeq(val: v, addr: &timer->hpet_config); |
496 | local_irq_save(flags); |
497 | |
498 | /* |
499 | * NOTE: First we modify the hidden accumulator |
500 | * register supported by periodic-capable comparators. |
501 | * We never want to modify the (single) counter; that |
502 | * would affect all the comparators. The value written |
503 | * is the counter value when the first interrupt is due. |
504 | */ |
505 | m = read_counter(&hpet->hpet_mc); |
506 | write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); |
507 | /* |
508 | * Then we modify the comparator, indicating the period |
509 | * for subsequent interrupt. |
510 | */ |
511 | write_counter(t, &timer->hpet_compare); |
512 | } else { |
513 | local_irq_save(flags); |
514 | m = read_counter(&hpet->hpet_mc); |
515 | write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); |
516 | } |
517 | |
518 | if (devp->hd_flags & HPET_SHARED_IRQ) { |
519 | isr = 1 << (devp - devp->hd_hpets->hp_dev); |
520 | writel(val: isr, addr: &hpet->hpet_isr); |
521 | } |
522 | writeq(val: g, addr: &timer->hpet_config); |
523 | local_irq_restore(flags); |
524 | |
525 | return 0; |
526 | } |
527 | |
528 | /* converts Hz to number of timer ticks */ |
529 | static inline unsigned long hpet_time_div(struct hpets *hpets, |
530 | unsigned long dis) |
531 | { |
532 | unsigned long long m; |
533 | |
534 | m = hpets->hp_tick_freq + (dis >> 1); |
535 | return div64_ul(m, dis); |
536 | } |
537 | |
538 | static int |
539 | hpet_ioctl_common(struct hpet_dev *devp, unsigned int cmd, unsigned long arg, |
540 | struct hpet_info *info) |
541 | { |
542 | struct hpet_timer __iomem *timer; |
543 | struct hpets *hpetp; |
544 | int err; |
545 | unsigned long v; |
546 | |
547 | switch (cmd) { |
548 | case HPET_IE_OFF: |
549 | case HPET_INFO: |
550 | case HPET_EPI: |
551 | case HPET_DPI: |
552 | case HPET_IRQFREQ: |
553 | timer = devp->hd_timer; |
554 | hpetp = devp->hd_hpets; |
555 | break; |
556 | case HPET_IE_ON: |
557 | return hpet_ioctl_ieon(devp); |
558 | default: |
559 | return -EINVAL; |
560 | } |
561 | |
562 | err = 0; |
563 | |
564 | switch (cmd) { |
565 | case HPET_IE_OFF: |
566 | if ((devp->hd_flags & HPET_IE) == 0) |
567 | break; |
568 | v = readq(addr: &timer->hpet_config); |
569 | v &= ~Tn_INT_ENB_CNF_MASK; |
570 | writeq(val: v, addr: &timer->hpet_config); |
571 | if (devp->hd_irq) { |
572 | free_irq(devp->hd_irq, devp); |
573 | devp->hd_irq = 0; |
574 | } |
575 | devp->hd_flags ^= HPET_IE; |
576 | break; |
577 | case HPET_INFO: |
578 | { |
579 | memset(info, 0, sizeof(*info)); |
580 | if (devp->hd_ireqfreq) |
581 | info->hi_ireqfreq = |
582 | hpet_time_div(hpets: hpetp, dis: devp->hd_ireqfreq); |
583 | info->hi_flags = |
584 | readq(addr: &timer->hpet_config) & Tn_PER_INT_CAP_MASK; |
585 | info->hi_hpet = hpetp->hp_which; |
586 | info->hi_timer = devp - hpetp->hp_dev; |
587 | break; |
588 | } |
589 | case HPET_EPI: |
590 | v = readq(addr: &timer->hpet_config); |
591 | if ((v & Tn_PER_INT_CAP_MASK) == 0) { |
592 | err = -ENXIO; |
593 | break; |
594 | } |
595 | devp->hd_flags |= HPET_PERIODIC; |
596 | break; |
597 | case HPET_DPI: |
598 | v = readq(addr: &timer->hpet_config); |
599 | if ((v & Tn_PER_INT_CAP_MASK) == 0) { |
600 | err = -ENXIO; |
601 | break; |
602 | } |
603 | if (devp->hd_flags & HPET_PERIODIC && |
604 | readq(addr: &timer->hpet_config) & Tn_TYPE_CNF_MASK) { |
605 | v = readq(addr: &timer->hpet_config); |
606 | v ^= Tn_TYPE_CNF_MASK; |
607 | writeq(val: v, addr: &timer->hpet_config); |
608 | } |
609 | devp->hd_flags &= ~HPET_PERIODIC; |
610 | break; |
611 | case HPET_IRQFREQ: |
612 | if ((arg > hpet_max_freq) && |
613 | !capable(CAP_SYS_RESOURCE)) { |
614 | err = -EACCES; |
615 | break; |
616 | } |
617 | |
618 | if (!arg) { |
619 | err = -EINVAL; |
620 | break; |
621 | } |
622 | |
623 | devp->hd_ireqfreq = hpet_time_div(hpets: hpetp, dis: arg); |
624 | } |
625 | |
626 | return err; |
627 | } |
628 | |
629 | static long |
630 | hpet_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
631 | { |
632 | struct hpet_info info; |
633 | int err; |
634 | |
635 | mutex_lock(&hpet_mutex); |
636 | err = hpet_ioctl_common(devp: file->private_data, cmd, arg, info: &info); |
637 | mutex_unlock(lock: &hpet_mutex); |
638 | |
639 | if ((cmd == HPET_INFO) && !err && |
640 | (copy_to_user(to: (void __user *)arg, from: &info, n: sizeof(info)))) |
641 | err = -EFAULT; |
642 | |
643 | return err; |
644 | } |
645 | |
646 | #ifdef CONFIG_COMPAT |
647 | struct compat_hpet_info { |
648 | compat_ulong_t hi_ireqfreq; /* Hz */ |
649 | compat_ulong_t hi_flags; /* information */ |
650 | unsigned short hi_hpet; |
651 | unsigned short hi_timer; |
652 | }; |
653 | |
654 | static long |
655 | hpet_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
656 | { |
657 | struct hpet_info info; |
658 | int err; |
659 | |
660 | mutex_lock(&hpet_mutex); |
661 | err = hpet_ioctl_common(devp: file->private_data, cmd, arg, info: &info); |
662 | mutex_unlock(lock: &hpet_mutex); |
663 | |
664 | if ((cmd == HPET_INFO) && !err) { |
665 | struct compat_hpet_info __user *u = compat_ptr(uptr: arg); |
666 | if (put_user(info.hi_ireqfreq, &u->hi_ireqfreq) || |
667 | put_user(info.hi_flags, &u->hi_flags) || |
668 | put_user(info.hi_hpet, &u->hi_hpet) || |
669 | put_user(info.hi_timer, &u->hi_timer)) |
670 | err = -EFAULT; |
671 | } |
672 | |
673 | return err; |
674 | } |
675 | #endif |
676 | |
677 | static const struct file_operations hpet_fops = { |
678 | .owner = THIS_MODULE, |
679 | .llseek = no_llseek, |
680 | .read = hpet_read, |
681 | .poll = hpet_poll, |
682 | .unlocked_ioctl = hpet_ioctl, |
683 | #ifdef CONFIG_COMPAT |
684 | .compat_ioctl = hpet_compat_ioctl, |
685 | #endif |
686 | .open = hpet_open, |
687 | .release = hpet_release, |
688 | .fasync = hpet_fasync, |
689 | .mmap = hpet_mmap, |
690 | }; |
691 | |
692 | static int hpet_is_known(struct hpet_data *hdp) |
693 | { |
694 | struct hpets *hpetp; |
695 | |
696 | for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) |
697 | if (hpetp->hp_hpet_phys == hdp->hd_phys_address) |
698 | return 1; |
699 | |
700 | return 0; |
701 | } |
702 | |
703 | static struct ctl_table hpet_table[] = { |
704 | { |
705 | .procname = "max-user-freq" , |
706 | .data = &hpet_max_freq, |
707 | .maxlen = sizeof(int), |
708 | .mode = 0644, |
709 | .proc_handler = proc_dointvec, |
710 | }, |
711 | }; |
712 | |
713 | static struct ctl_table_header *; |
714 | |
715 | /* |
716 | * Adjustment for when arming the timer with |
717 | * initial conditions. That is, main counter |
718 | * ticks expired before interrupts are enabled. |
719 | */ |
720 | #define TICK_CALIBRATE (1000UL) |
721 | |
722 | static unsigned long __hpet_calibrate(struct hpets *hpetp) |
723 | { |
724 | struct hpet_timer __iomem *timer = NULL; |
725 | unsigned long t, m, count, i, flags, start; |
726 | struct hpet_dev *devp; |
727 | int j; |
728 | struct hpet __iomem *hpet; |
729 | |
730 | for (j = 0, devp = hpetp->hp_dev; j < hpetp->hp_ntimer; j++, devp++) |
731 | if ((devp->hd_flags & HPET_OPEN) == 0) { |
732 | timer = devp->hd_timer; |
733 | break; |
734 | } |
735 | |
736 | if (!timer) |
737 | return 0; |
738 | |
739 | hpet = hpetp->hp_hpet; |
740 | t = read_counter(&timer->hpet_compare); |
741 | |
742 | i = 0; |
743 | count = hpet_time_div(hpets: hpetp, TICK_CALIBRATE); |
744 | |
745 | local_irq_save(flags); |
746 | |
747 | start = read_counter(&hpet->hpet_mc); |
748 | |
749 | do { |
750 | m = read_counter(&hpet->hpet_mc); |
751 | write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); |
752 | } while (i++, (m - start) < count); |
753 | |
754 | local_irq_restore(flags); |
755 | |
756 | return (m - start) / i; |
757 | } |
758 | |
759 | static unsigned long hpet_calibrate(struct hpets *hpetp) |
760 | { |
761 | unsigned long ret = ~0UL; |
762 | unsigned long tmp; |
763 | |
764 | /* |
765 | * Try to calibrate until return value becomes stable small value. |
766 | * If SMI interruption occurs in calibration loop, the return value |
767 | * will be big. This avoids its impact. |
768 | */ |
769 | for ( ; ; ) { |
770 | tmp = __hpet_calibrate(hpetp); |
771 | if (ret <= tmp) |
772 | break; |
773 | ret = tmp; |
774 | } |
775 | |
776 | return ret; |
777 | } |
778 | |
779 | int hpet_alloc(struct hpet_data *hdp) |
780 | { |
781 | u64 cap, mcfg; |
782 | struct hpet_dev *devp; |
783 | u32 i, ntimer; |
784 | struct hpets *hpetp; |
785 | struct hpet __iomem *hpet; |
786 | static struct hpets *last; |
787 | unsigned long period; |
788 | unsigned long long temp; |
789 | u32 remainder; |
790 | |
791 | /* |
792 | * hpet_alloc can be called by platform dependent code. |
793 | * If platform dependent code has allocated the hpet that |
794 | * ACPI has also reported, then we catch it here. |
795 | */ |
796 | if (hpet_is_known(hdp)) { |
797 | printk(KERN_DEBUG "%s: duplicate HPET ignored\n" , |
798 | __func__); |
799 | return 0; |
800 | } |
801 | |
802 | hpetp = kzalloc(struct_size(hpetp, hp_dev, hdp->hd_nirqs), |
803 | GFP_KERNEL); |
804 | |
805 | if (!hpetp) |
806 | return -ENOMEM; |
807 | |
808 | hpetp->hp_which = hpet_nhpet++; |
809 | hpetp->hp_hpet = hdp->hd_address; |
810 | hpetp->hp_hpet_phys = hdp->hd_phys_address; |
811 | |
812 | hpetp->hp_ntimer = hdp->hd_nirqs; |
813 | |
814 | for (i = 0; i < hdp->hd_nirqs; i++) |
815 | hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i]; |
816 | |
817 | hpet = hpetp->hp_hpet; |
818 | |
819 | cap = readq(addr: &hpet->hpet_cap); |
820 | |
821 | ntimer = ((cap & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT) + 1; |
822 | |
823 | if (hpetp->hp_ntimer != ntimer) { |
824 | printk(KERN_WARNING "hpet: number irqs doesn't agree" |
825 | " with number of timers\n" ); |
826 | kfree(objp: hpetp); |
827 | return -ENODEV; |
828 | } |
829 | |
830 | if (last) |
831 | last->hp_next = hpetp; |
832 | else |
833 | hpets = hpetp; |
834 | |
835 | last = hpetp; |
836 | |
837 | period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >> |
838 | HPET_COUNTER_CLK_PERIOD_SHIFT; /* fs, 10^-15 */ |
839 | temp = 1000000000000000uLL; /* 10^15 femtoseconds per second */ |
840 | temp += period >> 1; /* round */ |
841 | do_div(temp, period); |
842 | hpetp->hp_tick_freq = temp; /* ticks per second */ |
843 | |
844 | printk(KERN_INFO "hpet%d: at MMIO 0x%lx, IRQ%s" , |
845 | hpetp->hp_which, hdp->hd_phys_address, |
846 | hpetp->hp_ntimer > 1 ? "s" : "" ); |
847 | for (i = 0; i < hpetp->hp_ntimer; i++) |
848 | printk(KERN_CONT "%s %d" , i > 0 ? "," : "" , hdp->hd_irq[i]); |
849 | printk(KERN_CONT "\n" ); |
850 | |
851 | temp = hpetp->hp_tick_freq; |
852 | remainder = do_div(temp, 1000000); |
853 | printk(KERN_INFO |
854 | "hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n" , |
855 | hpetp->hp_which, hpetp->hp_ntimer, |
856 | cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, |
857 | (unsigned) temp, remainder); |
858 | |
859 | mcfg = readq(addr: &hpet->hpet_config); |
860 | if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { |
861 | write_counter(0L, &hpet->hpet_mc); |
862 | mcfg |= HPET_ENABLE_CNF_MASK; |
863 | writeq(val: mcfg, addr: &hpet->hpet_config); |
864 | } |
865 | |
866 | for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer; i++, devp++) { |
867 | struct hpet_timer __iomem *timer; |
868 | |
869 | timer = &hpet->hpet_timers[devp - hpetp->hp_dev]; |
870 | |
871 | devp->hd_hpets = hpetp; |
872 | devp->hd_hpet = hpet; |
873 | devp->hd_timer = timer; |
874 | |
875 | /* |
876 | * If the timer was reserved by platform code, |
877 | * then make timer unavailable for opens. |
878 | */ |
879 | if (hdp->hd_state & (1 << i)) { |
880 | devp->hd_flags = HPET_OPEN; |
881 | continue; |
882 | } |
883 | |
884 | init_waitqueue_head(&devp->hd_waitqueue); |
885 | } |
886 | |
887 | hpetp->hp_delta = hpet_calibrate(hpetp); |
888 | |
889 | return 0; |
890 | } |
891 | |
892 | static acpi_status hpet_resources(struct acpi_resource *res, void *data) |
893 | { |
894 | struct hpet_data *hdp; |
895 | acpi_status status; |
896 | struct acpi_resource_address64 addr; |
897 | |
898 | hdp = data; |
899 | |
900 | status = acpi_resource_to_address64(resource: res, out: &addr); |
901 | |
902 | if (ACPI_SUCCESS(status)) { |
903 | hdp->hd_phys_address = addr.address.minimum; |
904 | hdp->hd_address = ioremap(offset: addr.address.minimum, size: addr.address.address_length); |
905 | if (!hdp->hd_address) |
906 | return AE_ERROR; |
907 | |
908 | if (hpet_is_known(hdp)) { |
909 | iounmap(addr: hdp->hd_address); |
910 | return AE_ALREADY_EXISTS; |
911 | } |
912 | } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { |
913 | struct acpi_resource_fixed_memory32 *fixmem32; |
914 | |
915 | fixmem32 = &res->data.fixed_memory32; |
916 | |
917 | hdp->hd_phys_address = fixmem32->address; |
918 | hdp->hd_address = ioremap(offset: fixmem32->address, |
919 | HPET_RANGE_SIZE); |
920 | if (!hdp->hd_address) |
921 | return AE_ERROR; |
922 | |
923 | if (hpet_is_known(hdp)) { |
924 | iounmap(addr: hdp->hd_address); |
925 | return AE_ALREADY_EXISTS; |
926 | } |
927 | } else if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { |
928 | struct acpi_resource_extended_irq *irqp; |
929 | int i, irq; |
930 | |
931 | irqp = &res->data.extended_irq; |
932 | |
933 | for (i = 0; i < irqp->interrupt_count; i++) { |
934 | if (hdp->hd_nirqs >= HPET_MAX_TIMERS) |
935 | break; |
936 | |
937 | irq = acpi_register_gsi(NULL, gsi: irqp->interrupts[i], |
938 | triggering: irqp->triggering, |
939 | polarity: irqp->polarity); |
940 | if (irq < 0) |
941 | return AE_ERROR; |
942 | |
943 | hdp->hd_irq[hdp->hd_nirqs] = irq; |
944 | hdp->hd_nirqs++; |
945 | } |
946 | } |
947 | |
948 | return AE_OK; |
949 | } |
950 | |
951 | static int hpet_acpi_add(struct acpi_device *device) |
952 | { |
953 | acpi_status result; |
954 | struct hpet_data data; |
955 | |
956 | memset(&data, 0, sizeof(data)); |
957 | |
958 | result = |
959 | acpi_walk_resources(device: device->handle, METHOD_NAME__CRS, |
960 | user_function: hpet_resources, context: &data); |
961 | |
962 | if (ACPI_FAILURE(result)) |
963 | return -ENODEV; |
964 | |
965 | if (!data.hd_address || !data.hd_nirqs) { |
966 | if (data.hd_address) |
967 | iounmap(addr: data.hd_address); |
968 | printk("%s: no address or irqs in _CRS\n" , __func__); |
969 | return -ENODEV; |
970 | } |
971 | |
972 | return hpet_alloc(hdp: &data); |
973 | } |
974 | |
975 | static const struct acpi_device_id hpet_device_ids[] = { |
976 | {"PNP0103" , 0}, |
977 | {"" , 0}, |
978 | }; |
979 | |
980 | static struct acpi_driver hpet_acpi_driver = { |
981 | .name = "hpet" , |
982 | .ids = hpet_device_ids, |
983 | .ops = { |
984 | .add = hpet_acpi_add, |
985 | }, |
986 | }; |
987 | |
988 | static struct miscdevice hpet_misc = { HPET_MINOR, "hpet" , &hpet_fops }; |
989 | |
990 | static int __init hpet_init(void) |
991 | { |
992 | int result; |
993 | |
994 | result = misc_register(misc: &hpet_misc); |
995 | if (result < 0) |
996 | return -ENODEV; |
997 | |
998 | sysctl_header = register_sysctl("dev/hpet" , hpet_table); |
999 | |
1000 | result = acpi_bus_register_driver(driver: &hpet_acpi_driver); |
1001 | if (result < 0) { |
1002 | if (sysctl_header) |
1003 | unregister_sysctl_table(table: sysctl_header); |
1004 | misc_deregister(misc: &hpet_misc); |
1005 | return result; |
1006 | } |
1007 | |
1008 | return 0; |
1009 | } |
1010 | device_initcall(hpet_init); |
1011 | |
1012 | /* |
1013 | MODULE_AUTHOR("Bob Picco <Robert.Picco@hp.com>"); |
1014 | MODULE_LICENSE("GPL"); |
1015 | */ |
1016 | |