1*9ef1f84bSDavid du Colombier /*
2*9ef1f84bSDavid du Colombier * Performance counters non portable part
3*9ef1f84bSDavid du Colombier */
4*9ef1f84bSDavid du Colombier
5*9ef1f84bSDavid du Colombier #include "u.h"
6*9ef1f84bSDavid du Colombier #include "../port/lib.h"
7*9ef1f84bSDavid du Colombier #include "mem.h"
8*9ef1f84bSDavid du Colombier #include "dat.h"
9*9ef1f84bSDavid du Colombier #include "fns.h"
10*9ef1f84bSDavid du Colombier #include "../port/error.h"
11*9ef1f84bSDavid du Colombier
12*9ef1f84bSDavid du Colombier #include "amd64.h"
13*9ef1f84bSDavid du Colombier #include "pmc.h"
14*9ef1f84bSDavid du Colombier
15*9ef1f84bSDavid du Colombier typedef struct PmcCfg PmcCfg;
16*9ef1f84bSDavid du Colombier typedef struct PmcCore PmcCore;
17*9ef1f84bSDavid du Colombier
18*9ef1f84bSDavid du Colombier enum {
19*9ef1f84bSDavid du Colombier PeUnk,
20*9ef1f84bSDavid du Colombier PeAmd,
21*9ef1f84bSDavid du Colombier /*
22*9ef1f84bSDavid du Colombier * See Vol 3B Intel
23*9ef1f84bSDavid du Colombier * 64 Architecture's Software Developer's manual
24*9ef1f84bSDavid du Colombier */
25*9ef1f84bSDavid du Colombier PeIntel,
26*9ef1f84bSDavid du Colombier };
27*9ef1f84bSDavid du Colombier
28*9ef1f84bSDavid du Colombier enum {
29*9ef1f84bSDavid du Colombier _PeUnk,
30*9ef1f84bSDavid du Colombier /* Non architectural */
31*9ef1f84bSDavid du Colombier PeIntelSandy,
32*9ef1f84bSDavid du Colombier PeIntelNehalem,
33*9ef1f84bSDavid du Colombier PeIntelWestmere,
34*9ef1f84bSDavid du Colombier /*
35*9ef1f84bSDavid du Colombier * See BKDG for AMD cfg.family 10 Processors
36*9ef1f84bSDavid du Colombier * section 2.16 and 3.14
37*9ef1f84bSDavid du Colombier */
38*9ef1f84bSDavid du Colombier PeK10,
39*9ef1f84bSDavid du Colombier
40*9ef1f84bSDavid du Colombier };
41*9ef1f84bSDavid du Colombier
42*9ef1f84bSDavid du Colombier enum {
43*9ef1f84bSDavid du Colombier PeNregAmd = 4, /* Number of Pe/Pct regs for K10 */
44*9ef1f84bSDavid du Colombier };
45*9ef1f84bSDavid du Colombier
46*9ef1f84bSDavid du Colombier enum { /* MSRs */
47*9ef1f84bSDavid du Colombier PerfCtrbaseIntel= 0x000000c1, /* Performance Counters */
48*9ef1f84bSDavid du Colombier PerfEvtbaseIntel= 0x00000186, /* Performance Event Select */
49*9ef1f84bSDavid du Colombier PerfGlobalCtr = 0x0000038f, /* Performance Event Global Ctrl, intel */
50*9ef1f84bSDavid du Colombier
51*9ef1f84bSDavid du Colombier PerfEvtbaseAmd = 0xc0010000, /* Performance Event Select */
52*9ef1f84bSDavid du Colombier PerfCtrbaseAmd = 0xc0010004, /* Performance Counters */
53*9ef1f84bSDavid du Colombier };
54*9ef1f84bSDavid du Colombier
55*9ef1f84bSDavid du Colombier enum { /* HW Performance Counters Event Selector */
56*9ef1f84bSDavid du Colombier
57*9ef1f84bSDavid du Colombier PeHo = 0x0000020000000000ull,/* Host only */
58*9ef1f84bSDavid du Colombier PeGo = 0x0000010000000000ull,/* Guest only */
59*9ef1f84bSDavid du Colombier PeEvMskH = 0x0000000f00000000ull,/* Event mask H */
60*9ef1f84bSDavid du Colombier PeCtMsk = 0x00000000ff000000ull,/* Counter mask */
61*9ef1f84bSDavid du Colombier PeInMsk = 0x0000000000800000ull,/* Invert mask */
62*9ef1f84bSDavid du Colombier PeCtEna = 0x0000000000400000ull,/* Counter enable */
63*9ef1f84bSDavid du Colombier PeInEna = 0x0000000000100000ull,/* Interrupt enable */
64*9ef1f84bSDavid du Colombier PePnCtl = 0x0000000000080000ull,/* Pin control */
65*9ef1f84bSDavid du Colombier PeEdg = 0x0000000000040000ull,/* Edge detect */
66*9ef1f84bSDavid du Colombier PeOS = 0x0000000000020000ull,/* OS mode */
67*9ef1f84bSDavid du Colombier PeUsr = 0x0000000000010000ull,/* User mode */
68*9ef1f84bSDavid du Colombier PeUnMsk = 0x000000000000ff00ull,/* Unit Mask */
69*9ef1f84bSDavid du Colombier PeEvMskL = 0x00000000000000ffull,/* Event Mask L */
70*9ef1f84bSDavid du Colombier
71*9ef1f84bSDavid du Colombier PeEvMsksh = 32ull, /* Event mask shift */
72*9ef1f84bSDavid du Colombier };
73*9ef1f84bSDavid du Colombier
74*9ef1f84bSDavid du Colombier struct PmcCfg {
75*9ef1f84bSDavid du Colombier int nregs;
76*9ef1f84bSDavid du Colombier u32int ctrbase;
77*9ef1f84bSDavid du Colombier u32int evtbase;
78*9ef1f84bSDavid du Colombier int vendor;
79*9ef1f84bSDavid du Colombier int family;
80*9ef1f84bSDavid du Colombier PmcCtlCtrId *pmcidsarch;
81*9ef1f84bSDavid du Colombier PmcCtlCtrId *pmcids;
82*9ef1f84bSDavid du Colombier };
83*9ef1f84bSDavid du Colombier
84*9ef1f84bSDavid du Colombier extern int pmcdebug;
85*9ef1f84bSDavid du Colombier
86*9ef1f84bSDavid du Colombier static PmcCfg cfg;
87*9ef1f84bSDavid du Colombier static PmcCore pmccore[MACHMAX];
88*9ef1f84bSDavid du Colombier
89*9ef1f84bSDavid du Colombier static void pmcmachupdate(void);
90*9ef1f84bSDavid du Colombier
91*9ef1f84bSDavid du Colombier int
pmcnregs(void)92*9ef1f84bSDavid du Colombier pmcnregs(void)
93*9ef1f84bSDavid du Colombier {
94*9ef1f84bSDavid du Colombier u32int info[4];
95*9ef1f84bSDavid du Colombier int nregs;
96*9ef1f84bSDavid du Colombier
97*9ef1f84bSDavid du Colombier if(cfg.nregs != 0)
98*9ef1f84bSDavid du Colombier return cfg.nregs; /* don't call cpuid more than necessary */
99*9ef1f84bSDavid du Colombier switch(cfg.vendor){
100*9ef1f84bSDavid du Colombier case PeAmd:
101*9ef1f84bSDavid du Colombier nregs = PeNregAmd;
102*9ef1f84bSDavid du Colombier break;
103*9ef1f84bSDavid du Colombier case PeIntel:
104*9ef1f84bSDavid du Colombier cpuid(0xa, 0, info);
105*9ef1f84bSDavid du Colombier nregs = (info[0]>>8)&0xff;
106*9ef1f84bSDavid du Colombier break;
107*9ef1f84bSDavid du Colombier default:
108*9ef1f84bSDavid du Colombier nregs = 0;
109*9ef1f84bSDavid du Colombier }
110*9ef1f84bSDavid du Colombier if(nregs > PmcMaxCtrs)
111*9ef1f84bSDavid du Colombier nregs = PmcMaxCtrs;
112*9ef1f84bSDavid du Colombier return nregs;
113*9ef1f84bSDavid du Colombier }
114*9ef1f84bSDavid du Colombier
115*9ef1f84bSDavid du Colombier static u64int
pmcmsk(void)116*9ef1f84bSDavid du Colombier pmcmsk(void)
117*9ef1f84bSDavid du Colombier {
118*9ef1f84bSDavid du Colombier u32int info[4];
119*9ef1f84bSDavid du Colombier u64int msk;
120*9ef1f84bSDavid du Colombier
121*9ef1f84bSDavid du Colombier msk = 0;
122*9ef1f84bSDavid du Colombier switch(cfg.vendor){
123*9ef1f84bSDavid du Colombier case PeAmd:
124*9ef1f84bSDavid du Colombier msk = ~0ULL;
125*9ef1f84bSDavid du Colombier break;
126*9ef1f84bSDavid du Colombier case PeIntel:
127*9ef1f84bSDavid du Colombier cpuid(0xa, 0, info);
128*9ef1f84bSDavid du Colombier msk = (1<<((info[0]>>16)&0xff)) - 1;
129*9ef1f84bSDavid du Colombier break;
130*9ef1f84bSDavid du Colombier }
131*9ef1f84bSDavid du Colombier return msk;
132*9ef1f84bSDavid du Colombier }
133*9ef1f84bSDavid du Colombier
134*9ef1f84bSDavid du Colombier PmcCtlCtrId pmcidsk10[] = {
135*9ef1f84bSDavid du Colombier {"locked instr", "0x024 0x1"},
136*9ef1f84bSDavid du Colombier {"locked cycles nonspecul", "0x024 0x4"}, /* in cycles */
137*9ef1f84bSDavid du Colombier {"SMI intr", "0x02b 0x0"},
138*9ef1f84bSDavid du Colombier {"DC access", "0x040 0x0"},
139*9ef1f84bSDavid du Colombier {"DC miss", "0x041 0x0"},
140*9ef1f84bSDavid du Colombier {"DC refills", "0x042 0x1f"},
141*9ef1f84bSDavid du Colombier {"DC evicted", "0x042 0x3f"},
142*9ef1f84bSDavid du Colombier {"L1 DTLB miss", "0x045 0x7"}, /* DTLB L2 hits */
143*9ef1f84bSDavid du Colombier {"L2 DTLB miss", "0x046 0x7"},
144*9ef1f84bSDavid du Colombier {"L1 DTLB hit", "0x04d 0x3"},
145*9ef1f84bSDavid du Colombier {"global TLB flush", "0x054 0x0"},
146*9ef1f84bSDavid du Colombier {"L2 hit", "0x07d 0x3f"},
147*9ef1f84bSDavid du Colombier {"L2 miss", "0x07e 0xf"},
148*9ef1f84bSDavid du Colombier {"IC miss", "0x081 0x0"},
149*9ef1f84bSDavid du Colombier {"IC refill from L2", "0x082 0x0"},
150*9ef1f84bSDavid du Colombier {"IC refill from system", "0x083 0x0"},
151*9ef1f84bSDavid du Colombier {"L1 ITLB miss", "0x084 0x0"}, /* L2 ITLB hits */
152*9ef1f84bSDavid du Colombier {"L2 ITLB miss", "0x085 0x3"},
153*9ef1f84bSDavid du Colombier {"DRAM access", "0x0e0 0x3f"},
154*9ef1f84bSDavid du Colombier //{"L3 miss core 0", "0x4e1 0x13"},
155*9ef1f84bSDavid du Colombier //{"L3 miss core 1", "0x4e1 0x23"},
156*9ef1f84bSDavid du Colombier //{"L3 miss core 2", "0x4e1 0x43"},
157*9ef1f84bSDavid du Colombier //{"L3 miss core 3", "0x4e1 0x83"},
158*9ef1f84bSDavid du Colombier {"L3 miss", "0x4e1 0xf3"}, /* all cores in the socket */
159*9ef1f84bSDavid du Colombier {"", ""},
160*9ef1f84bSDavid du Colombier };
161*9ef1f84bSDavid du Colombier
162*9ef1f84bSDavid du Colombier /*18.2.3 Intel Software Deveveloper's Manual */
163*9ef1f84bSDavid du Colombier PmcCtlCtrId pmcidsintel[] = {
164*9ef1f84bSDavid du Colombier {"unhalted cycles", "0x3c 0x0"},
165*9ef1f84bSDavid du Colombier {"instr", "0xc0 0x0"},
166*9ef1f84bSDavid du Colombier {"Llast misses", "0x2e 0x41"},
167*9ef1f84bSDavid du Colombier {"branch instr", "0xc4 0x0"},
168*9ef1f84bSDavid du Colombier {"branch misses", "0xc5 0x0 "},
169*9ef1f84bSDavid du Colombier {"", ""},
170*9ef1f84bSDavid du Colombier };
171*9ef1f84bSDavid du Colombier
172*9ef1f84bSDavid du Colombier /* Table 19.7 Intel Software Deveveloper's Manual */
173*9ef1f84bSDavid du Colombier PmcCtlCtrId pmcidsandy[] = {
174*9ef1f84bSDavid du Colombier {"DTLB walk cycles", "0x49 0x4"}, /* all levels */
175*9ef1f84bSDavid du Colombier {"DTLB miss", "0x8 0x2"},
176*9ef1f84bSDavid du Colombier {"DTLB hit", "0x8 0x4"},
177*9ef1f84bSDavid du Colombier {"L2 hit", "0x24 0x4"},
178*9ef1f84bSDavid du Colombier {"L2 miss", "0x24 0x8"},
179*9ef1f84bSDavid du Colombier {"IL2 hit", "0x24 0x10"},
180*9ef1f84bSDavid du Colombier {"IL2 miss", "0x24 0x20"},
181*9ef1f84bSDavid du Colombier {"ITLB miss", "0x85 0x2"},
182*9ef1f84bSDavid du Colombier {"ITLB walk cycles", "0x85 0x4"},
183*9ef1f84bSDavid du Colombier {"ITLB flush", "0xae 0x1"},
184*9ef1f84bSDavid du Colombier {"mem loads", "0xd0 0xf1"}, /* counts μops */
185*9ef1f84bSDavid du Colombier {"mem stores", "0xd0 0xf2"},
186*9ef1f84bSDavid du Colombier {"mem ops", "0xd0 0xf3"},
187*9ef1f84bSDavid du Colombier {"", ""},
188*9ef1f84bSDavid du Colombier };
189*9ef1f84bSDavid du Colombier
190*9ef1f84bSDavid du Colombier #define X86MODEL(x) ((((x)>>4) & 0x0F) | (((x)>>16) & 0x0F)<<4)
191*9ef1f84bSDavid du Colombier #define X86FAMILY(x) ((((x)>>8) & 0x0F) | (((x)>>20) & 0xFF)<<4)
192*9ef1f84bSDavid du Colombier
193*9ef1f84bSDavid du Colombier static int
pmcintelfamily(void)194*9ef1f84bSDavid du Colombier pmcintelfamily(void)
195*9ef1f84bSDavid du Colombier {
196*9ef1f84bSDavid du Colombier u32int info, fam, mod;
197*9ef1f84bSDavid du Colombier
198*9ef1f84bSDavid du Colombier info = m->cpuinfo[1][0];
199*9ef1f84bSDavid du Colombier
200*9ef1f84bSDavid du Colombier fam = X86FAMILY(info);
201*9ef1f84bSDavid du Colombier mod = X86MODEL(info);
202*9ef1f84bSDavid du Colombier if(fam != 0x6)
203*9ef1f84bSDavid du Colombier return PeUnk;
204*9ef1f84bSDavid du Colombier switch(mod){
205*9ef1f84bSDavid du Colombier case 0x2a:
206*9ef1f84bSDavid du Colombier return PeIntelSandy;
207*9ef1f84bSDavid du Colombier case 0x1a:
208*9ef1f84bSDavid du Colombier case 0x1e:
209*9ef1f84bSDavid du Colombier case 0x1f:
210*9ef1f84bSDavid du Colombier return PeIntelNehalem;
211*9ef1f84bSDavid du Colombier case 0x25:
212*9ef1f84bSDavid du Colombier case 0x2c:
213*9ef1f84bSDavid du Colombier return PeIntelWestmere;
214*9ef1f84bSDavid du Colombier }
215*9ef1f84bSDavid du Colombier return PeUnk;
216*9ef1f84bSDavid du Colombier }
217*9ef1f84bSDavid du Colombier
218*9ef1f84bSDavid du Colombier void
pmcinitctl(PmcCtl * p)219*9ef1f84bSDavid du Colombier pmcinitctl(PmcCtl *p)
220*9ef1f84bSDavid du Colombier {
221*9ef1f84bSDavid du Colombier memset(p, 0xff, sizeof(PmcCtl));
222*9ef1f84bSDavid du Colombier p->enab = PmcCtlNullval;
223*9ef1f84bSDavid du Colombier p->user = PmcCtlNullval;
224*9ef1f84bSDavid du Colombier p->os = PmcCtlNullval;
225*9ef1f84bSDavid du Colombier p->nodesc = 1;
226*9ef1f84bSDavid du Colombier }
227*9ef1f84bSDavid du Colombier
228*9ef1f84bSDavid du Colombier void
pmcconfigure(void)229*9ef1f84bSDavid du Colombier pmcconfigure(void)
230*9ef1f84bSDavid du Colombier {
231*9ef1f84bSDavid du Colombier Mach *mach;
232*9ef1f84bSDavid du Colombier int i, j, isrecog;
233*9ef1f84bSDavid du Colombier
234*9ef1f84bSDavid du Colombier isrecog = 0;
235*9ef1f84bSDavid du Colombier
236*9ef1f84bSDavid du Colombier if(memcmp(&m->cpuinfo[0][1], "AuthcAMDenti", 12) == 0){
237*9ef1f84bSDavid du Colombier isrecog++;
238*9ef1f84bSDavid du Colombier cfg.ctrbase = PerfCtrbaseAmd;
239*9ef1f84bSDavid du Colombier cfg.evtbase = PerfEvtbaseAmd;
240*9ef1f84bSDavid du Colombier cfg.vendor = PeAmd;
241*9ef1f84bSDavid du Colombier cfg.family = PeUnk;
242*9ef1f84bSDavid du Colombier cfg.pmcidsarch = pmcidsk10;
243*9ef1f84bSDavid du Colombier }else if(memcmp(&m->cpuinfo[0][1], "GenuntelineI", 12) == 0){
244*9ef1f84bSDavid du Colombier isrecog++;
245*9ef1f84bSDavid du Colombier cfg.ctrbase = PerfCtrbaseIntel;
246*9ef1f84bSDavid du Colombier cfg.evtbase = PerfEvtbaseIntel;
247*9ef1f84bSDavid du Colombier cfg.vendor = PeIntel;
248*9ef1f84bSDavid du Colombier cfg.family = pmcintelfamily();
249*9ef1f84bSDavid du Colombier cfg.pmcidsarch = pmcidsintel;
250*9ef1f84bSDavid du Colombier switch(cfg.family){
251*9ef1f84bSDavid du Colombier case PeIntelSandy:
252*9ef1f84bSDavid du Colombier cfg.pmcids = pmcidsandy;
253*9ef1f84bSDavid du Colombier break;
254*9ef1f84bSDavid du Colombier case PeIntelNehalem:
255*9ef1f84bSDavid du Colombier case PeIntelWestmere:
256*9ef1f84bSDavid du Colombier break;
257*9ef1f84bSDavid du Colombier }
258*9ef1f84bSDavid du Colombier }else
259*9ef1f84bSDavid du Colombier cfg.vendor = PeUnk;
260*9ef1f84bSDavid du Colombier
261*9ef1f84bSDavid du Colombier cfg.nregs = pmcnregs();
262*9ef1f84bSDavid du Colombier if(isrecog)
263*9ef1f84bSDavid du Colombier pmcupdate = pmcmachupdate;
264*9ef1f84bSDavid du Colombier
265*9ef1f84bSDavid du Colombier for(i = 0; i < MACHMAX; i++) {
266*9ef1f84bSDavid du Colombier if((mach = sys->machptr[i]) != nil && mach->online != 0){
267*9ef1f84bSDavid du Colombier for(j = 0; j < cfg.nregs; j++)
268*9ef1f84bSDavid du Colombier pmcinitctl(&pmccore[i].ctr[j]);
269*9ef1f84bSDavid du Colombier }
270*9ef1f84bSDavid du Colombier }
271*9ef1f84bSDavid du Colombier }
272*9ef1f84bSDavid du Colombier
273*9ef1f84bSDavid du Colombier static void
pmcenab(void)274*9ef1f84bSDavid du Colombier pmcenab(void)
275*9ef1f84bSDavid du Colombier {
276*9ef1f84bSDavid du Colombier switch(cfg.vendor){
277*9ef1f84bSDavid du Colombier case PeAmd:
278*9ef1f84bSDavid du Colombier return;
279*9ef1f84bSDavid du Colombier case PeIntel:
280*9ef1f84bSDavid du Colombier wrmsr(PerfGlobalCtr, pmcmsk());
281*9ef1f84bSDavid du Colombier break;
282*9ef1f84bSDavid du Colombier }
283*9ef1f84bSDavid du Colombier }
284*9ef1f84bSDavid du Colombier
285*9ef1f84bSDavid du Colombier /* so they can be read from user space */
286*9ef1f84bSDavid du Colombier static int
pmcuserenab(int enable)287*9ef1f84bSDavid du Colombier pmcuserenab(int enable)
288*9ef1f84bSDavid du Colombier {
289*9ef1f84bSDavid du Colombier u64int cr4;
290*9ef1f84bSDavid du Colombier
291*9ef1f84bSDavid du Colombier cr4 = cr4get();
292*9ef1f84bSDavid du Colombier if (enable){
293*9ef1f84bSDavid du Colombier cr4 |= Pce;
294*9ef1f84bSDavid du Colombier } else
295*9ef1f84bSDavid du Colombier cr4 &= ~Pce;
296*9ef1f84bSDavid du Colombier cr4put(cr4);
297*9ef1f84bSDavid du Colombier return cr4&Pce;
298*9ef1f84bSDavid du Colombier }
299*9ef1f84bSDavid du Colombier
300*9ef1f84bSDavid du Colombier int
pmctrans(PmcCtl * p)301*9ef1f84bSDavid du Colombier pmctrans(PmcCtl *p)
302*9ef1f84bSDavid du Colombier {
303*9ef1f84bSDavid du Colombier PmcCtlCtrId *pi;
304*9ef1f84bSDavid du Colombier int n;
305*9ef1f84bSDavid du Colombier
306*9ef1f84bSDavid du Colombier n = 0;
307*9ef1f84bSDavid du Colombier if(cfg.pmcidsarch != nil)
308*9ef1f84bSDavid du Colombier for (pi = &cfg.pmcidsarch[0]; pi->portdesc[0] != '\0'; pi++){
309*9ef1f84bSDavid du Colombier if (strncmp(p->descstr, pi->portdesc, strlen(pi->portdesc)) == 0){
310*9ef1f84bSDavid du Colombier strncpy(p->descstr, pi->archdesc, strlen(pi->archdesc) + 1);
311*9ef1f84bSDavid du Colombier n = 1;
312*9ef1f84bSDavid du Colombier break;
313*9ef1f84bSDavid du Colombier }
314*9ef1f84bSDavid du Colombier }
315*9ef1f84bSDavid du Colombier /* this ones supersede the other ones */
316*9ef1f84bSDavid du Colombier if(cfg.pmcids != nil)
317*9ef1f84bSDavid du Colombier for (pi = &cfg.pmcids[0]; pi->portdesc[0] != '\0'; pi++){
318*9ef1f84bSDavid du Colombier if (strncmp(p->descstr, pi->portdesc, strlen(pi->portdesc)) == 0){
319*9ef1f84bSDavid du Colombier strncpy(p->descstr, pi->archdesc, strlen(pi->archdesc) + 1);
320*9ef1f84bSDavid du Colombier n = 1;
321*9ef1f84bSDavid du Colombier break;
322*9ef1f84bSDavid du Colombier }
323*9ef1f84bSDavid du Colombier }
324*9ef1f84bSDavid du Colombier if(pmcdebug != 0)
325*9ef1f84bSDavid du Colombier print("really setting %s\n", p->descstr);
326*9ef1f84bSDavid du Colombier return n;
327*9ef1f84bSDavid du Colombier }
328*9ef1f84bSDavid du Colombier
329*9ef1f84bSDavid du Colombier //PeHo|PeGo
330*9ef1f84bSDavid du Colombier #define PeAll (PeOS|PeUsr)
331*9ef1f84bSDavid du Colombier #define SetEvMsk(v, e) ((v)|(((e)&PeEvMskL)|(((e)<<(PeEvMsksh-8))&PeEvMskH)))
332*9ef1f84bSDavid du Colombier #define SetUMsk(v, u) ((v)|(((u)<<8ull)&PeUnMsk))
333*9ef1f84bSDavid du Colombier
334*9ef1f84bSDavid du Colombier #define GetEvMsk(e) (((e)&PeEvMskL)|(((e)&PeEvMskH)>>(PeEvMsksh-8)))
335*9ef1f84bSDavid du Colombier #define GetUMsk(u) (((u)&PeUnMsk)>>8ull)
336*9ef1f84bSDavid du Colombier
337*9ef1f84bSDavid du Colombier static int
getctl(PmcCtl * p,u32int regno)338*9ef1f84bSDavid du Colombier getctl(PmcCtl *p, u32int regno)
339*9ef1f84bSDavid du Colombier {
340*9ef1f84bSDavid du Colombier u64int r, e, u;
341*9ef1f84bSDavid du Colombier
342*9ef1f84bSDavid du Colombier r = rdmsr(regno + cfg.evtbase);
343*9ef1f84bSDavid du Colombier p->enab = (r&PeCtEna) != 0;
344*9ef1f84bSDavid du Colombier p->user = (r&PeUsr) != 0;
345*9ef1f84bSDavid du Colombier p->os = (r&PeOS) != 0;
346*9ef1f84bSDavid du Colombier e = GetEvMsk(r);
347*9ef1f84bSDavid du Colombier u = GetUMsk(r);
348*9ef1f84bSDavid du Colombier /* TODO inverse translation */
349*9ef1f84bSDavid du Colombier snprint(p->descstr, KNAMELEN, "%#ullx %#ullx", e, u);
350*9ef1f84bSDavid du Colombier p->nodesc = 0;
351*9ef1f84bSDavid du Colombier return 0;
352*9ef1f84bSDavid du Colombier }
353*9ef1f84bSDavid du Colombier
354*9ef1f84bSDavid du Colombier static int
pmcanyenab(void)355*9ef1f84bSDavid du Colombier pmcanyenab(void)
356*9ef1f84bSDavid du Colombier {
357*9ef1f84bSDavid du Colombier int i;
358*9ef1f84bSDavid du Colombier PmcCtl p;
359*9ef1f84bSDavid du Colombier
360*9ef1f84bSDavid du Colombier for (i = 0; i < cfg.nregs; i++) {
361*9ef1f84bSDavid du Colombier if (getctl(&p, i) < 0)
362*9ef1f84bSDavid du Colombier return -1;
363*9ef1f84bSDavid du Colombier if (p.enab)
364*9ef1f84bSDavid du Colombier return 1;
365*9ef1f84bSDavid du Colombier }
366*9ef1f84bSDavid du Colombier
367*9ef1f84bSDavid du Colombier return 0;
368*9ef1f84bSDavid du Colombier }
369*9ef1f84bSDavid du Colombier
370*9ef1f84bSDavid du Colombier
371*9ef1f84bSDavid du Colombier static int
setctl(PmcCtl * p,int regno)372*9ef1f84bSDavid du Colombier setctl(PmcCtl *p, int regno)
373*9ef1f84bSDavid du Colombier {
374*9ef1f84bSDavid du Colombier u64int v, e, u;
375*9ef1f84bSDavid du Colombier char *toks[2];
376*9ef1f84bSDavid du Colombier char str[KNAMELEN];
377*9ef1f84bSDavid du Colombier
378*9ef1f84bSDavid du Colombier v = rdmsr(regno + cfg.evtbase);
379*9ef1f84bSDavid du Colombier v &= PeEvMskH|PeEvMskL|PeCtEna|PeOS|PeUsr|PeUnMsk;
380*9ef1f84bSDavid du Colombier if (p->enab != PmcCtlNullval)
381*9ef1f84bSDavid du Colombier if (p->enab)
382*9ef1f84bSDavid du Colombier v |= PeCtEna;
383*9ef1f84bSDavid du Colombier else
384*9ef1f84bSDavid du Colombier v &= ~PeCtEna;
385*9ef1f84bSDavid du Colombier
386*9ef1f84bSDavid du Colombier if (p->user != PmcCtlNullval)
387*9ef1f84bSDavid du Colombier if (p->user)
388*9ef1f84bSDavid du Colombier v |= PeUsr;
389*9ef1f84bSDavid du Colombier else
390*9ef1f84bSDavid du Colombier v &= ~PeUsr;
391*9ef1f84bSDavid du Colombier
392*9ef1f84bSDavid du Colombier if (p->os != PmcCtlNullval)
393*9ef1f84bSDavid du Colombier if (p->os)
394*9ef1f84bSDavid du Colombier v |= PeOS;
395*9ef1f84bSDavid du Colombier else
396*9ef1f84bSDavid du Colombier v &= ~PeOS;
397*9ef1f84bSDavid du Colombier
398*9ef1f84bSDavid du Colombier if (pmctrans(p) < 0)
399*9ef1f84bSDavid du Colombier return -1;
400*9ef1f84bSDavid du Colombier
401*9ef1f84bSDavid du Colombier if (p->nodesc == 0) {
402*9ef1f84bSDavid du Colombier memmove(str, p->descstr, KNAMELEN);
403*9ef1f84bSDavid du Colombier if (tokenize(str, toks, 2) != 2)
404*9ef1f84bSDavid du Colombier return -1;
405*9ef1f84bSDavid du Colombier e = atoi(toks[0]);
406*9ef1f84bSDavid du Colombier u = atoi(toks[1]);
407*9ef1f84bSDavid du Colombier v &= ~(PeEvMskL|PeEvMskH|PeUnMsk);
408*9ef1f84bSDavid du Colombier v |= SetEvMsk(v, e);
409*9ef1f84bSDavid du Colombier v |= SetUMsk(v, u);
410*9ef1f84bSDavid du Colombier }
411*9ef1f84bSDavid du Colombier wrmsr(regno+ cfg.evtbase, v);
412*9ef1f84bSDavid du Colombier pmcuserenab(pmcanyenab());
413*9ef1f84bSDavid du Colombier if (pmcdebug) {
414*9ef1f84bSDavid du Colombier v = rdmsr(regno+ cfg.evtbase);
415*9ef1f84bSDavid du Colombier print("conf pmc[%#ux]: %#llux\n", regno, v);
416*9ef1f84bSDavid du Colombier }
417*9ef1f84bSDavid du Colombier return 0;
418*9ef1f84bSDavid du Colombier }
419*9ef1f84bSDavid du Colombier
420*9ef1f84bSDavid du Colombier int
pmcdescstr(char * str,int nstr)421*9ef1f84bSDavid du Colombier pmcdescstr(char *str, int nstr)
422*9ef1f84bSDavid du Colombier {
423*9ef1f84bSDavid du Colombier PmcCtlCtrId *pi;
424*9ef1f84bSDavid du Colombier int ns;
425*9ef1f84bSDavid du Colombier
426*9ef1f84bSDavid du Colombier ns = 0;
427*9ef1f84bSDavid du Colombier
428*9ef1f84bSDavid du Colombier if(pmcdebug != 0)
429*9ef1f84bSDavid du Colombier print("vendor %x family %x nregs %d pmcnregs %d\n", cfg.vendor, cfg.family, cfg.nregs, pmcnregs());
430*9ef1f84bSDavid du Colombier if(cfg.pmcidsarch == nil && cfg.pmcids == nil){
431*9ef1f84bSDavid du Colombier *str = 0;
432*9ef1f84bSDavid du Colombier return ns;
433*9ef1f84bSDavid du Colombier }
434*9ef1f84bSDavid du Colombier
435*9ef1f84bSDavid du Colombier if(cfg.pmcidsarch != nil)
436*9ef1f84bSDavid du Colombier for (pi = &cfg.pmcidsarch[0]; pi->portdesc[0] != '\0'; pi++)
437*9ef1f84bSDavid du Colombier ns += snprint(str + ns, nstr - ns, "%s\n",pi->portdesc);
438*9ef1f84bSDavid du Colombier if(cfg.pmcids != nil)
439*9ef1f84bSDavid du Colombier for (pi = &cfg.pmcids[0]; pi->portdesc[0] != '\0'; pi++)
440*9ef1f84bSDavid du Colombier ns += snprint(str + ns, nstr - ns, "%s\n",pi->portdesc);
441*9ef1f84bSDavid du Colombier return ns;
442*9ef1f84bSDavid du Colombier }
443*9ef1f84bSDavid du Colombier
444*9ef1f84bSDavid du Colombier static u64int
getctr(u32int regno)445*9ef1f84bSDavid du Colombier getctr(u32int regno)
446*9ef1f84bSDavid du Colombier {
447*9ef1f84bSDavid du Colombier return rdmsr(regno + cfg.ctrbase);
448*9ef1f84bSDavid du Colombier }
449*9ef1f84bSDavid du Colombier
450*9ef1f84bSDavid du Colombier static int
setctr(u64int v,u32int regno)451*9ef1f84bSDavid du Colombier setctr(u64int v, u32int regno)
452*9ef1f84bSDavid du Colombier {
453*9ef1f84bSDavid du Colombier wrmsr(regno + cfg.ctrbase, v);
454*9ef1f84bSDavid du Colombier return 0;
455*9ef1f84bSDavid du Colombier }
456*9ef1f84bSDavid du Colombier
457*9ef1f84bSDavid du Colombier u64int
pmcgetctr(u32int coreno,u32int regno)458*9ef1f84bSDavid du Colombier pmcgetctr(u32int coreno, u32int regno)
459*9ef1f84bSDavid du Colombier {
460*9ef1f84bSDavid du Colombier PmcCtr *p;
461*9ef1f84bSDavid du Colombier u64int ctr;
462*9ef1f84bSDavid du Colombier
463*9ef1f84bSDavid du Colombier if (regno >= cfg.nregs)
464*9ef1f84bSDavid du Colombier error("invalid reg");
465*9ef1f84bSDavid du Colombier p = &pmccore[coreno].ctr[regno];
466*9ef1f84bSDavid du Colombier
467*9ef1f84bSDavid du Colombier ilock(&pmccore[coreno]);
468*9ef1f84bSDavid du Colombier if(coreno == m->machno)
469*9ef1f84bSDavid du Colombier ctr = getctr(regno);
470*9ef1f84bSDavid du Colombier else
471*9ef1f84bSDavid du Colombier ctr = p->ctr;
472*9ef1f84bSDavid du Colombier iunlock(&pmccore[coreno]);
473*9ef1f84bSDavid du Colombier
474*9ef1f84bSDavid du Colombier return ctr;
475*9ef1f84bSDavid du Colombier }
476*9ef1f84bSDavid du Colombier
477*9ef1f84bSDavid du Colombier int
pmcsetctr(u32int coreno,u64int v,u32int regno)478*9ef1f84bSDavid du Colombier pmcsetctr(u32int coreno, u64int v, u32int regno)
479*9ef1f84bSDavid du Colombier {
480*9ef1f84bSDavid du Colombier PmcCtr *p;
481*9ef1f84bSDavid du Colombier int n;
482*9ef1f84bSDavid du Colombier
483*9ef1f84bSDavid du Colombier if (regno >= cfg.nregs)
484*9ef1f84bSDavid du Colombier error("invalid reg");
485*9ef1f84bSDavid du Colombier p = &pmccore[coreno].ctr[regno];
486*9ef1f84bSDavid du Colombier
487*9ef1f84bSDavid du Colombier ilock(&pmccore[coreno]);
488*9ef1f84bSDavid du Colombier if(coreno == m->machno)
489*9ef1f84bSDavid du Colombier n = setctr(v, regno);
490*9ef1f84bSDavid du Colombier else{
491*9ef1f84bSDavid du Colombier p->ctr = v;
492*9ef1f84bSDavid du Colombier p->ctrset |= PmcSet;
493*9ef1f84bSDavid du Colombier p->stale = 1;
494*9ef1f84bSDavid du Colombier n = 0;
495*9ef1f84bSDavid du Colombier }
496*9ef1f84bSDavid du Colombier iunlock(&pmccore[coreno]);
497*9ef1f84bSDavid du Colombier
498*9ef1f84bSDavid du Colombier return n;
499*9ef1f84bSDavid du Colombier }
500*9ef1f84bSDavid du Colombier
501*9ef1f84bSDavid du Colombier static void
ctl2ctl(PmcCtl * dctl,PmcCtl * sctl)502*9ef1f84bSDavid du Colombier ctl2ctl(PmcCtl *dctl, PmcCtl *sctl)
503*9ef1f84bSDavid du Colombier {
504*9ef1f84bSDavid du Colombier if(sctl->enab != PmcCtlNullval)
505*9ef1f84bSDavid du Colombier dctl->enab = sctl->enab;
506*9ef1f84bSDavid du Colombier if(sctl->user != PmcCtlNullval)
507*9ef1f84bSDavid du Colombier dctl->user = sctl->user;
508*9ef1f84bSDavid du Colombier if(sctl->os != PmcCtlNullval)
509*9ef1f84bSDavid du Colombier dctl->os = sctl->os;
510*9ef1f84bSDavid du Colombier if(sctl->nodesc == 0) {
511*9ef1f84bSDavid du Colombier memmove(dctl->descstr, sctl->descstr, KNAMELEN);
512*9ef1f84bSDavid du Colombier dctl->nodesc = 0;
513*9ef1f84bSDavid du Colombier }
514*9ef1f84bSDavid du Colombier }
515*9ef1f84bSDavid du Colombier
516*9ef1f84bSDavid du Colombier int
pmcsetctl(u32int coreno,PmcCtl * pctl,u32int regno)517*9ef1f84bSDavid du Colombier pmcsetctl(u32int coreno, PmcCtl *pctl, u32int regno)
518*9ef1f84bSDavid du Colombier {
519*9ef1f84bSDavid du Colombier PmcCtr *p;
520*9ef1f84bSDavid du Colombier int n;
521*9ef1f84bSDavid du Colombier
522*9ef1f84bSDavid du Colombier if (regno >= cfg.nregs)
523*9ef1f84bSDavid du Colombier error("invalid reg");
524*9ef1f84bSDavid du Colombier p = &pmccore[coreno].ctr[regno];
525*9ef1f84bSDavid du Colombier
526*9ef1f84bSDavid du Colombier ilock(&pmccore[coreno]);
527*9ef1f84bSDavid du Colombier if(coreno == m->machno)
528*9ef1f84bSDavid du Colombier n = setctl(pctl, regno);
529*9ef1f84bSDavid du Colombier else{
530*9ef1f84bSDavid du Colombier ctl2ctl(&p->PmcCtl, pctl);
531*9ef1f84bSDavid du Colombier p->ctlset |= PmcSet;
532*9ef1f84bSDavid du Colombier p->stale = 1;
533*9ef1f84bSDavid du Colombier n = 0;
534*9ef1f84bSDavid du Colombier }
535*9ef1f84bSDavid du Colombier iunlock(&pmccore[coreno]);
536*9ef1f84bSDavid du Colombier
537*9ef1f84bSDavid du Colombier return n;
538*9ef1f84bSDavid du Colombier }
539*9ef1f84bSDavid du Colombier
540*9ef1f84bSDavid du Colombier int
pmcgetctl(u32int coreno,PmcCtl * pctl,u32int regno)541*9ef1f84bSDavid du Colombier pmcgetctl(u32int coreno, PmcCtl *pctl, u32int regno)
542*9ef1f84bSDavid du Colombier {
543*9ef1f84bSDavid du Colombier PmcCtr *p;
544*9ef1f84bSDavid du Colombier int n;
545*9ef1f84bSDavid du Colombier
546*9ef1f84bSDavid du Colombier if (regno >= cfg.nregs)
547*9ef1f84bSDavid du Colombier error("invalid reg");
548*9ef1f84bSDavid du Colombier p = &pmccore[coreno].ctr[regno];
549*9ef1f84bSDavid du Colombier
550*9ef1f84bSDavid du Colombier ilock(&pmccore[coreno]);
551*9ef1f84bSDavid du Colombier if(coreno == m->machno)
552*9ef1f84bSDavid du Colombier n = getctl(pctl, regno);
553*9ef1f84bSDavid du Colombier else{
554*9ef1f84bSDavid du Colombier memmove(pctl, &p->PmcCtl, sizeof(PmcCtl));
555*9ef1f84bSDavid du Colombier n = 0;
556*9ef1f84bSDavid du Colombier }
557*9ef1f84bSDavid du Colombier iunlock(&pmccore[coreno]);
558*9ef1f84bSDavid du Colombier
559*9ef1f84bSDavid du Colombier return n;
560*9ef1f84bSDavid du Colombier }
561*9ef1f84bSDavid du Colombier
562*9ef1f84bSDavid du Colombier static void
pmcmachupdate(void)563*9ef1f84bSDavid du Colombier pmcmachupdate(void)
564*9ef1f84bSDavid du Colombier {
565*9ef1f84bSDavid du Colombier PmcCtr *p;
566*9ef1f84bSDavid du Colombier int coreno, i, maxct;
567*9ef1f84bSDavid du Colombier
568*9ef1f84bSDavid du Colombier if((maxct = cfg.nregs) <= 0)
569*9ef1f84bSDavid du Colombier return;
570*9ef1f84bSDavid du Colombier coreno = m->machno;
571*9ef1f84bSDavid du Colombier
572*9ef1f84bSDavid du Colombier ilock(&pmccore[coreno]);
573*9ef1f84bSDavid du Colombier for (i = 0; i < maxct; i++) {
574*9ef1f84bSDavid du Colombier p = &pmccore[coreno].ctr[i];
575*9ef1f84bSDavid du Colombier if(p->ctrset & PmcSet)
576*9ef1f84bSDavid du Colombier setctr(p->ctr, i);
577*9ef1f84bSDavid du Colombier if(p->ctlset & PmcSet)
578*9ef1f84bSDavid du Colombier setctl(p, i);
579*9ef1f84bSDavid du Colombier p->ctr = getctr(i);
580*9ef1f84bSDavid du Colombier getctl(p, i);
581*9ef1f84bSDavid du Colombier p->ctrset = PmcIgn;
582*9ef1f84bSDavid du Colombier p->ctlset = PmcIgn;
583*9ef1f84bSDavid du Colombier p->stale = 0;
584*9ef1f84bSDavid du Colombier }
585*9ef1f84bSDavid du Colombier iunlock(&pmccore[coreno]);
586*9ef1f84bSDavid du Colombier }
587