xref: /plan9-contrib/sys/src/9k/386/pmcio.c (revision 49d76b4b10eb2f614c42c7db16ef9eb8cc20de58)
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