This source file includes following definitions.
- pctrattach
- pctropen
- pctrclose
- p5ctrsel
- p5ctrrd
- p6ctrsel
- p6ctrrd
- pctrioctl
1
2
3
4
5
6
7
8
9
10
11
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <sys/errno.h>
15 #include <sys/fcntl.h>
16 #include <sys/ioccom.h>
17 #include <sys/systm.h>
18
19 #include <machine/cputypes.h>
20 #include <machine/psl.h>
21 #include <machine/pctr.h>
22 #include <machine/cpu.h>
23 #include <machine/specialreg.h>
24
25 pctrval pctr_idlcnt;
26
27 int pctr_isintel;
28
29 #define usetsc (cpu_feature & CPUID_TSC)
30 #define usep5ctr (pctr_isintel && (((cpu_id >> 8) & 15) == 5) && \
31 (((cpu_id >> 4) & 15) > 0))
32 #define usep6ctr (pctr_isintel && ((cpu_id >> 8) & 15) == 6)
33
34 void pctrattach(int);
35 int pctropen(dev_t, int, int, struct proc *);
36 int pctrclose(dev_t, int, int, struct proc *);
37 int pctrioctl(dev_t, u_long, caddr_t, int, struct proc *);
38 int p5ctrsel(int fflag, u_int cmd, u_int fn);
39 static __inline void p5ctrrd(struct pctrst *st);
40 int p6ctrsel(int fflag, u_int cmd, u_int fn);
41 static __inline void p6ctrrd(struct pctrst *st);
42
43 void
44 pctrattach(int num)
45 {
46 if (num > 1)
47 return;
48
49 pctr_isintel = (strcmp(cpu_vendor, "GenuineIntel") == 0);
50
51 if (usep6ctr)
52
53 __asm __volatile ("movl %%cr4,%%eax\n"
54 "\tandl %0,%%eax\n"
55 "\torl %1,%%eax\n"
56 "\tmovl %%eax,%%cr4"
57 :: "i" (~CR4_TSD), "i" (CR4_PCE) : "eax");
58 else if (usetsc)
59
60 __asm __volatile ("movl %%cr4,%%eax\n"
61 "\tandl %0,%%eax\n"
62 "\tmovl %%eax,%%cr4"
63 :: "i" (~CR4_TSD) : "eax");
64
65 if (usep6ctr)
66 printf("pctr: 686-class user-level performance counters enabled\n");
67 else if (usep5ctr)
68 printf("pctr: 586-class performance counters and user-level cycle counter enabled\n");
69 else if (usetsc)
70 printf("pctr: user-level cycle counter enabled\n");
71 else
72 printf("pctr: no performance counters in CPU\n");
73 }
74
75 int
76 pctropen(dev_t dev, int oflags, int devtype, struct proc *p)
77 {
78 if (minor(dev))
79 return ENXIO;
80 return 0;
81 }
82
83 int
84 pctrclose(dev_t dev, int oflags, int devtype, struct proc *p)
85 {
86 return 0;
87 }
88
89 int
90 p5ctrsel(int fflag, u_int cmd, u_int fn)
91 {
92 pctrval msr11;
93 int msr;
94 int shift;
95
96 cmd -= PCIOCS0;
97 if (cmd > 1)
98 return EINVAL;
99 msr = P5MSR_CTR0 + cmd;
100 shift = cmd ? 0x10 : 0;
101
102 if (!(fflag & FWRITE))
103 return EPERM;
104 if (fn >= 0x200)
105 return EINVAL;
106
107 msr11 = rdmsr(P5MSR_CTRSEL);
108 msr11 &= ~(0x1ffLL << shift);
109 msr11 |= fn << shift;
110 wrmsr(P5MSR_CTRSEL, msr11);
111 wrmsr(msr, 0);
112
113 return 0;
114 }
115
116 static __inline void
117 p5ctrrd(struct pctrst *st)
118 {
119 u_int msr11;
120
121 msr11 = rdmsr(P5MSR_CTRSEL);
122 st->pctr_fn[0] = msr11 & 0xffff;
123 st->pctr_fn[1] = msr11 >> 16;
124 __asm __volatile("cli");
125 st->pctr_tsc = rdtsc();
126 st->pctr_hwc[0] = rdmsr(P5MSR_CTR0);
127 st->pctr_hwc[1] = rdmsr(P5MSR_CTR1);
128 __asm __volatile("sti");
129 }
130
131 int
132 p6ctrsel(int fflag, u_int cmd, u_int fn)
133 {
134 int msrsel, msrval;
135
136 cmd -= PCIOCS0;
137 if (cmd > 1)
138 return EINVAL;
139 msrsel = P6MSR_CTRSEL0 + cmd;
140 msrval = P6MSR_CTR0 + cmd;
141
142 if (!(fflag & FWRITE))
143 return EPERM;
144 if (fn & 0x380000)
145 return EINVAL;
146
147 wrmsr(msrval, 0);
148 wrmsr(msrsel, fn);
149 wrmsr(msrval, 0);
150
151 return 0;
152 }
153
154 static __inline void
155 p6ctrrd(struct pctrst *st)
156 {
157 st->pctr_fn[0] = rdmsr(P6MSR_CTRSEL0);
158 st->pctr_fn[1] = rdmsr(P6MSR_CTRSEL1);
159 __asm __volatile("cli");
160 st->pctr_tsc = rdtsc();
161 st->pctr_hwc[0] = rdpmc(0);
162 st->pctr_hwc[1] = rdpmc(1);
163 __asm __volatile("sti");
164 }
165
166
167 int
168 pctrioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
169 {
170 switch (cmd) {
171 case PCIOCRD:
172 {
173 struct pctrst *st = (void *)data;
174
175 if (usep6ctr)
176 p6ctrrd(st);
177 else if (usep5ctr)
178 p5ctrrd(st);
179 else {
180 bzero(st, sizeof(*st));
181 if (usetsc)
182 st->pctr_tsc = rdtsc();
183 }
184 st->pctr_idl = pctr_idlcnt;
185 return 0;
186 }
187 case PCIOCS0:
188 case PCIOCS1:
189 if (usep6ctr)
190 return p6ctrsel(fflag, cmd, *(u_int *) data);
191 if (usep5ctr)
192 return p5ctrsel(fflag, cmd, *(u_int *) data);
193 return ENODEV;
194 default:
195 return EINVAL;
196 }
197 }