~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/powerpc/oprofile/op_model_rs64.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version
 
7
 * 2 of the License, or (at your option) any later version.
 
8
 */
 
9
 
 
10
#include <linux/oprofile.h>
 
11
#include <linux/init.h>
 
12
#include <linux/smp.h>
 
13
#include <asm/ptrace.h>
 
14
#include <asm/system.h>
 
15
#include <asm/processor.h>
 
16
#include <asm/cputable.h>
 
17
#include <asm/oprofile_impl.h>
 
18
 
 
19
#define dbg(args...)
 
20
 
 
21
static void ctrl_write(unsigned int i, unsigned int val)
 
22
{
 
23
        unsigned int tmp = 0;
 
24
        unsigned long shift = 0, mask = 0;
 
25
 
 
26
        dbg("ctrl_write %d %x\n", i, val);
 
27
 
 
28
        switch(i) {
 
29
        case 0:
 
30
                tmp = mfspr(SPRN_MMCR0);
 
31
                shift = 6;
 
32
                mask = 0x7F;
 
33
                break;
 
34
        case 1:
 
35
                tmp = mfspr(SPRN_MMCR0);
 
36
                shift = 0;
 
37
                mask = 0x3F;
 
38
                break;
 
39
        case 2:
 
40
                tmp = mfspr(SPRN_MMCR1);
 
41
                shift = 31 - 4;
 
42
                mask = 0x1F;
 
43
                break;
 
44
        case 3:
 
45
                tmp = mfspr(SPRN_MMCR1);
 
46
                shift = 31 - 9;
 
47
                mask = 0x1F;
 
48
                break;
 
49
        case 4:
 
50
                tmp = mfspr(SPRN_MMCR1);
 
51
                shift = 31 - 14;
 
52
                mask = 0x1F;
 
53
                break;
 
54
        case 5:
 
55
                tmp = mfspr(SPRN_MMCR1);
 
56
                shift = 31 - 19;
 
57
                mask = 0x1F;
 
58
                break;
 
59
        case 6:
 
60
                tmp = mfspr(SPRN_MMCR1);
 
61
                shift = 31 - 24;
 
62
                mask = 0x1F;
 
63
                break;
 
64
        case 7:
 
65
                tmp = mfspr(SPRN_MMCR1);
 
66
                shift = 31 - 28;
 
67
                mask = 0xF;
 
68
                break;
 
69
        }
 
70
 
 
71
        tmp = tmp & ~(mask << shift);
 
72
        tmp |= val << shift;
 
73
 
 
74
        switch(i) {
 
75
                case 0:
 
76
                case 1:
 
77
                        mtspr(SPRN_MMCR0, tmp);
 
78
                        break;
 
79
                default:
 
80
                        mtspr(SPRN_MMCR1, tmp);
 
81
        }
 
82
 
 
83
        dbg("ctrl_write mmcr0 %lx mmcr1 %lx\n", mfspr(SPRN_MMCR0),
 
84
               mfspr(SPRN_MMCR1));
 
85
}
 
86
 
 
87
static unsigned long reset_value[OP_MAX_COUNTER];
 
88
 
 
89
static int num_counters;
 
90
 
 
91
static int rs64_reg_setup(struct op_counter_config *ctr,
 
92
                           struct op_system_config *sys,
 
93
                           int num_ctrs)
 
94
{
 
95
        int i;
 
96
 
 
97
        num_counters = num_ctrs;
 
98
 
 
99
        for (i = 0; i < num_counters; ++i)
 
100
                reset_value[i] = 0x80000000UL - ctr[i].count;
 
101
 
 
102
        /* XXX setup user and kernel profiling */
 
103
        return 0;
 
104
}
 
105
 
 
106
static int rs64_cpu_setup(struct op_counter_config *ctr)
 
107
{
 
108
        unsigned int mmcr0;
 
109
 
 
110
        /* reset MMCR0 and set the freeze bit */
 
111
        mmcr0 = MMCR0_FC;
 
112
        mtspr(SPRN_MMCR0, mmcr0);
 
113
 
 
114
        /* reset MMCR1, MMCRA */
 
115
        mtspr(SPRN_MMCR1, 0);
 
116
 
 
117
        if (cpu_has_feature(CPU_FTR_MMCRA))
 
118
                mtspr(SPRN_MMCRA, 0);
 
119
 
 
120
        mmcr0 |= MMCR0_FCM1|MMCR0_PMXE|MMCR0_FCECE;
 
121
        /* Only applies to POWER3, but should be safe on RS64 */
 
122
        mmcr0 |= MMCR0_PMC1CE|MMCR0_PMCjCE;
 
123
        mtspr(SPRN_MMCR0, mmcr0);
 
124
 
 
125
        dbg("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(),
 
126
            mfspr(SPRN_MMCR0));
 
127
        dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
 
128
            mfspr(SPRN_MMCR1));
 
129
 
 
130
        return 0;
 
131
}
 
132
 
 
133
static int rs64_start(struct op_counter_config *ctr)
 
134
{
 
135
        int i;
 
136
        unsigned int mmcr0;
 
137
 
 
138
        /* set the PMM bit (see comment below) */
 
139
        mtmsrd(mfmsr() | MSR_PMM);
 
140
 
 
141
        for (i = 0; i < num_counters; ++i) {
 
142
                if (ctr[i].enabled) {
 
143
                        classic_ctr_write(i, reset_value[i]);
 
144
                        ctrl_write(i, ctr[i].event);
 
145
                } else {
 
146
                        classic_ctr_write(i, 0);
 
147
                }
 
148
        }
 
149
 
 
150
        mmcr0 = mfspr(SPRN_MMCR0);
 
151
 
 
152
        /*
 
153
         * now clear the freeze bit, counting will not start until we
 
154
         * rfid from this excetion, because only at that point will
 
155
         * the PMM bit be cleared
 
156
         */
 
157
        mmcr0 &= ~MMCR0_FC;
 
158
        mtspr(SPRN_MMCR0, mmcr0);
 
159
 
 
160
        dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
 
161
        return 0;
 
162
}
 
163
 
 
164
static void rs64_stop(void)
 
165
{
 
166
        unsigned int mmcr0;
 
167
 
 
168
        /* freeze counters */
 
169
        mmcr0 = mfspr(SPRN_MMCR0);
 
170
        mmcr0 |= MMCR0_FC;
 
171
        mtspr(SPRN_MMCR0, mmcr0);
 
172
 
 
173
        dbg("stop on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
 
174
 
 
175
        mb();
 
176
}
 
177
 
 
178
static void rs64_handle_interrupt(struct pt_regs *regs,
 
179
                                  struct op_counter_config *ctr)
 
180
{
 
181
        unsigned int mmcr0;
 
182
        int is_kernel;
 
183
        int val;
 
184
        int i;
 
185
        unsigned long pc = mfspr(SPRN_SIAR);
 
186
 
 
187
        is_kernel = is_kernel_addr(pc);
 
188
 
 
189
        /* set the PMM bit (see comment below) */
 
190
        mtmsrd(mfmsr() | MSR_PMM);
 
191
 
 
192
        for (i = 0; i < num_counters; ++i) {
 
193
                val = classic_ctr_read(i);
 
194
                if (val < 0) {
 
195
                        if (ctr[i].enabled) {
 
196
                                oprofile_add_ext_sample(pc, regs, i, is_kernel);
 
197
                                classic_ctr_write(i, reset_value[i]);
 
198
                        } else {
 
199
                                classic_ctr_write(i, 0);
 
200
                        }
 
201
                }
 
202
        }
 
203
 
 
204
        mmcr0 = mfspr(SPRN_MMCR0);
 
205
 
 
206
        /* reset the perfmon trigger */
 
207
        mmcr0 |= MMCR0_PMXE;
 
208
 
 
209
        /*
 
210
         * now clear the freeze bit, counting will not start until we
 
211
         * rfid from this exception, because only at that point will
 
212
         * the PMM bit be cleared
 
213
         */
 
214
        mmcr0 &= ~MMCR0_FC;
 
215
        mtspr(SPRN_MMCR0, mmcr0);
 
216
}
 
217
 
 
218
struct op_powerpc_model op_model_rs64 = {
 
219
        .reg_setup              = rs64_reg_setup,
 
220
        .cpu_setup              = rs64_cpu_setup,
 
221
        .start                  = rs64_start,
 
222
        .stop                   = rs64_stop,
 
223
        .handle_interrupt       = rs64_handle_interrupt,
 
224
};