Merge HEAD from /spare/repo/linux-2.6/.git
[linux-2.6] / arch / ppc64 / kernel / pmc.c
1 /*
2  *  linux/arch/ppc64/kernel/pmc.c
3  *
4  *  Copyright (C) 2004 David Gibson, IBM Corporation.
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation; either version
9  *  2 of the License, or (at your option) any later version.
10  */
11
12 #include <linux/config.h>
13 #include <linux/errno.h>
14 #include <linux/spinlock.h>
15 #include <linux/module.h>
16
17 #include <asm/processor.h>
18 #include <asm/pmc.h>
19
20 /* Ensure exceptions are disabled */
21 static void dummy_perf(struct pt_regs *regs)
22 {
23         unsigned int mmcr0 = mfspr(SPRN_MMCR0);
24
25         mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO);
26         mtspr(SPRN_MMCR0, mmcr0);
27 }
28
29 static spinlock_t pmc_owner_lock = SPIN_LOCK_UNLOCKED;
30 static void *pmc_owner_caller; /* mostly for debugging */
31 perf_irq_t perf_irq = dummy_perf;
32
33 int reserve_pmc_hardware(perf_irq_t new_perf_irq)
34 {
35         int err = 0;
36
37         spin_lock(&pmc_owner_lock);
38
39         if (pmc_owner_caller) {
40                 printk(KERN_WARNING "reserve_pmc_hardware: "
41                        "PMC hardware busy (reserved by caller %p)\n",
42                        pmc_owner_caller);
43                 err = -EBUSY;
44                 goto out;
45         }
46
47         pmc_owner_caller = __builtin_return_address(0);
48         perf_irq = new_perf_irq ? : dummy_perf;
49
50  out:
51         spin_unlock(&pmc_owner_lock);
52         return err;
53 }
54 EXPORT_SYMBOL_GPL(reserve_pmc_hardware);
55
56 void release_pmc_hardware(void)
57 {
58         spin_lock(&pmc_owner_lock);
59
60         WARN_ON(! pmc_owner_caller);
61
62         pmc_owner_caller = NULL;
63         perf_irq = dummy_perf;
64
65         spin_unlock(&pmc_owner_lock);
66 }
67 EXPORT_SYMBOL_GPL(release_pmc_hardware);
68
69 void power4_enable_pmcs(void)
70 {
71         unsigned long hid0;
72
73         hid0 = mfspr(HID0);
74         hid0 |= 1UL << (63 - 20);
75
76         /* POWER4 requires the following sequence */
77         asm volatile(
78                 "sync\n"
79                 "mtspr     %1, %0\n"
80                 "mfspr     %0, %1\n"
81                 "mfspr     %0, %1\n"
82                 "mfspr     %0, %1\n"
83                 "mfspr     %0, %1\n"
84                 "mfspr     %0, %1\n"
85                 "mfspr     %0, %1\n"
86                 "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0):
87                 "memory");
88 }