OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [hpet.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.