xref: /plan9-contrib/sys/src/9/pc/mpacpi.c (revision 00a4193c1e0554905f959f11961389c706f63ac9)
1abfa367dSDavid du Colombier /*
2abfa367dSDavid du Colombier  * minimal acpi support for multiprocessors.
3abfa367dSDavid du Colombier  *
4abfa367dSDavid du Colombier  * avoids AML but that's only enough to discover
5abfa367dSDavid du Colombier  * the processors, not the interrupt routing details.
6abfa367dSDavid du Colombier  */
7abfa367dSDavid du Colombier #include "u.h"
8abfa367dSDavid du Colombier #include "../port/lib.h"
9abfa367dSDavid du Colombier #include "mem.h"
10abfa367dSDavid du Colombier #include "dat.h"
11abfa367dSDavid du Colombier #include "fns.h"
12abfa367dSDavid du Colombier #include "io.h"
13abfa367dSDavid du Colombier #include "mp.h"
14abfa367dSDavid du Colombier #include "mpacpi.h"
15abfa367dSDavid du Colombier 
16abfa367dSDavid du Colombier /* 8c says: out of fixed registers */
17abfa367dSDavid du Colombier #define L64GET(p)	((uvlong)L32GET((p)+4) << 32 | L32GET(p))
18abfa367dSDavid du Colombier 
19abfa367dSDavid du Colombier enum {
20abfa367dSDavid du Colombier 	/* apic types */
21abfa367dSDavid du Colombier 	Apiclproc,
22abfa367dSDavid du Colombier 	Apicio,
23abfa367dSDavid du Colombier 	Apicintrsrcoverride,
24abfa367dSDavid du Colombier 	Apicnmisrc,
25abfa367dSDavid du Colombier 	Apiclnmi,
26abfa367dSDavid du Colombier 	Apicladdroverride,
27abfa367dSDavid du Colombier 	Apicios,
28abfa367dSDavid du Colombier 	Apicls,
29abfa367dSDavid du Colombier 	Apicintrsrc,
30abfa367dSDavid du Colombier 	Apiclx2,
31abfa367dSDavid du Colombier 	Apiclx2nmi,
32abfa367dSDavid du Colombier 
33abfa367dSDavid du Colombier 	PcmpUsed = 1ul<<31,		/* Apic->flags addition */
34abfa367dSDavid du Colombier 
35abfa367dSDavid du Colombier 	Lapicbase = 0x1b,		/* msr */
36abfa367dSDavid du Colombier 
37abfa367dSDavid du Colombier 	Lapicae	= 1<<11,		/* apic enable in Lapicbase */
38abfa367dSDavid du Colombier };
39abfa367dSDavid du Colombier 
40abfa367dSDavid du Colombier #define dprint(...)	if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
41abfa367dSDavid du Colombier 
42abfa367dSDavid du Colombier /* from mp.c */
43abfa367dSDavid du Colombier int	mpdebug;
44abfa367dSDavid du Colombier int	mpmachno;
45abfa367dSDavid du Colombier Apic	mpapic[MaxAPICNO+1];
46abfa367dSDavid du Colombier int	machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */
47abfa367dSDavid du Colombier 
48abfa367dSDavid du Colombier Apic	*bootapic;
49abfa367dSDavid du Colombier 
50abfa367dSDavid du Colombier static int nprocid;
51abfa367dSDavid du Colombier 
52abfa367dSDavid du Colombier static uvlong
l64get(uchar * p)53abfa367dSDavid du Colombier l64get(uchar *p)
54abfa367dSDavid du Colombier {
55abfa367dSDavid du Colombier 	return L64GET(p);
56abfa367dSDavid du Colombier }
57abfa367dSDavid du Colombier 
58abfa367dSDavid du Colombier int
apicset(Apic * apic,int type,int apicno,int f)59abfa367dSDavid du Colombier apicset(Apic *apic, int type, int apicno, int f)
60abfa367dSDavid du Colombier {
61abfa367dSDavid du Colombier 	if(apicno > MaxAPICNO)
62abfa367dSDavid du Colombier 		return -1;
63abfa367dSDavid du Colombier 	apic->type = type;
64abfa367dSDavid du Colombier 	apic->apicno = apicno;
65abfa367dSDavid du Colombier 	apic->flags = f | PcmpEN | PcmpUsed;
66abfa367dSDavid du Colombier 	return 0;
67abfa367dSDavid du Colombier }
68abfa367dSDavid du Colombier 
69abfa367dSDavid du Colombier int
mpnewproc(Apic * apic,int apicno,int f)70abfa367dSDavid du Colombier mpnewproc(Apic *apic, int apicno, int f)
71abfa367dSDavid du Colombier {
72abfa367dSDavid du Colombier 	if(apic->flags & PcmpUsed) {
73abfa367dSDavid du Colombier 		print("mpnewproc: apic already enabled\n");
74abfa367dSDavid du Colombier 		return -1;
75abfa367dSDavid du Colombier 	}
76abfa367dSDavid du Colombier 	if (apicset(apic, PcmpPROCESSOR, apicno, f) < 0)
77abfa367dSDavid du Colombier 		return -1;
78abfa367dSDavid du Colombier 	apic->lintr[1] = apic->lintr[0] = ApicIMASK;
79abfa367dSDavid du Colombier 	/* botch! just enumerate */
80abfa367dSDavid du Colombier 	if(apic->flags & PcmpBP)
81abfa367dSDavid du Colombier 		apic->machno = 0;
82abfa367dSDavid du Colombier 	else
83abfa367dSDavid du Colombier 		apic->machno = ++mpmachno;
84abfa367dSDavid du Colombier 	machno2apicno[apic->machno] = apicno;
85abfa367dSDavid du Colombier 	return 0;
86abfa367dSDavid du Colombier }
87abfa367dSDavid du Colombier 
88abfa367dSDavid du Colombier static int
mpacpiproc(uchar * p,ulong laddr)89abfa367dSDavid du Colombier mpacpiproc(uchar *p, ulong laddr)
90abfa367dSDavid du Colombier {
91abfa367dSDavid du Colombier 	int id, f;
92abfa367dSDavid du Colombier 	ulong *vladdr;
93abfa367dSDavid du Colombier 	vlong base;
94abfa367dSDavid du Colombier 	char *already;
95abfa367dSDavid du Colombier 	Apic *apic;
96abfa367dSDavid du Colombier 
97abfa367dSDavid du Colombier 	/* p bytes: type (0), len (8), cpuid, cpu_lapic id, flags[4] */
98abfa367dSDavid du Colombier 	id = p[3];
99abfa367dSDavid du Colombier 	/* cpu unusable flag or id out of range? */
100abfa367dSDavid du Colombier 	if((L32GET(p+4) & 1) == 0 || id > MaxAPICNO)
101abfa367dSDavid du Colombier 		return -1;
102abfa367dSDavid du Colombier 
103abfa367dSDavid du Colombier 	vladdr = nil;
104abfa367dSDavid du Colombier 	already = "";
105abfa367dSDavid du Colombier 	f = 0;
106abfa367dSDavid du Colombier 	apic = &mpapic[id];
107*00a4193cSDavid du Colombier 	dprint("\tmpacpiproc: apic %#p\n", apic);
108abfa367dSDavid du Colombier 	apic->paddr = laddr;
109abfa367dSDavid du Colombier 	if (nprocid++ == 0) {
110abfa367dSDavid du Colombier 		f = PcmpBP;
111abfa367dSDavid du Colombier 		vladdr = vmap(apic->paddr, 1024);
112abfa367dSDavid du Colombier 		if(apic->addr == nil){
113abfa367dSDavid du Colombier 			print("proc apic %d: failed to map %#p\n", id,
114abfa367dSDavid du Colombier 				apic->paddr);
115abfa367dSDavid du Colombier 			already = "(fail)";
116abfa367dSDavid du Colombier 		}
117abfa367dSDavid du Colombier 		bootapic = apic;
118abfa367dSDavid du Colombier 	}
119abfa367dSDavid du Colombier 	apic->addr = vladdr;
120abfa367dSDavid du Colombier 
121abfa367dSDavid du Colombier 	if(apic->flags & PcmpUsed)
122abfa367dSDavid du Colombier 		already = "(on)";
123abfa367dSDavid du Colombier 	else
124abfa367dSDavid du Colombier 		mpnewproc(apic, id, f);
125abfa367dSDavid du Colombier 
126abfa367dSDavid du Colombier 	if (0)
127abfa367dSDavid du Colombier 		dprint("\tapic proc %d/%d apicid %d flags%s%s %s\n", nprocid-1,
128abfa367dSDavid du Colombier 			apic->machno, id, f & PcmpBP? " boot": "",
129abfa367dSDavid du Colombier 			f & PcmpEN? " enabled": "", already);
130abfa367dSDavid du Colombier 	USED(already);
131abfa367dSDavid du Colombier 
132abfa367dSDavid du Colombier 	rdmsr(Lapicbase, &base);
133abfa367dSDavid du Colombier 	if (!(base & Lapicae)) {
134abfa367dSDavid du Colombier 		dprint("mpacpiproc: enabling lapic\n");
135abfa367dSDavid du Colombier 		wrmsr(Lapicbase, base | Lapicae);
136abfa367dSDavid du Colombier 	}
137abfa367dSDavid du Colombier 	return 0;
138abfa367dSDavid du Colombier }
139abfa367dSDavid du Colombier 
140abfa367dSDavid du Colombier static void
mpacpicpus(Madt * madt)141abfa367dSDavid du Colombier mpacpicpus(Madt *madt)
142abfa367dSDavid du Colombier {
143abfa367dSDavid du Colombier 	int i, n;
144abfa367dSDavid du Colombier 	ulong laddr;
145abfa367dSDavid du Colombier 	uchar *p;
146abfa367dSDavid du Colombier 
147abfa367dSDavid du Colombier 	laddr = L32GET(madt->addr);
148*00a4193cSDavid du Colombier 	dprint("APIC mpacpicpus(%#p) lapic addr %#lux, flags %#ux\n",
149*00a4193cSDavid du Colombier 		madt, laddr, L32GET(madt->flags));
150abfa367dSDavid du Colombier 
151abfa367dSDavid du Colombier 	n = L32GET(&madt->sdthdr[4]);
152abfa367dSDavid du Colombier 	p = madt->structures;
153*00a4193cSDavid du Colombier 	dprint("\t%d structures at %#p\n",n, p);
154abfa367dSDavid du Colombier 	/* byte 0 is assumed to be type, 1 is assumed to be length */
155abfa367dSDavid du Colombier 	for(i = offsetof(Madt, structures[0]); i < n; i += p[1], p += p[1])
156abfa367dSDavid du Colombier 		switch(p[0]){
157abfa367dSDavid du Colombier 		case Apiclproc:
158abfa367dSDavid du Colombier 			mpacpiproc(p, laddr);
159abfa367dSDavid du Colombier 			break;
160abfa367dSDavid du Colombier 		}
161abfa367dSDavid du Colombier }
162abfa367dSDavid du Colombier 
163abfa367dSDavid du Colombier /* returns nil iff checksum is bad */
164abfa367dSDavid du Colombier static void *
mpacpirsdchecksum(void * addr,int length)165abfa367dSDavid du Colombier mpacpirsdchecksum(void* addr, int length)
166abfa367dSDavid du Colombier {
167abfa367dSDavid du Colombier 	uchar *p, sum;
168abfa367dSDavid du Colombier 
169abfa367dSDavid du Colombier 	sum = 0;
170abfa367dSDavid du Colombier 	for(p = addr; length-- > 0; p++)
171abfa367dSDavid du Colombier 		sum += *p;
172abfa367dSDavid du Colombier 	return sum == 0? addr: nil;
173abfa367dSDavid du Colombier }
174abfa367dSDavid du Colombier 
175abfa367dSDavid du Colombier /* call func for each acpi table found */
176abfa367dSDavid du Colombier static void
mpacpiscan(void (* func)(uchar *))177abfa367dSDavid du Colombier mpacpiscan(void (*func)(uchar *))
178abfa367dSDavid du Colombier {
179abfa367dSDavid du Colombier 	int asize, i, tbllen, sdtlen;
180abfa367dSDavid du Colombier 	uintptr dhpa, sdtpa;
181abfa367dSDavid du Colombier 	uchar *tbl, *sdt;
182abfa367dSDavid du Colombier 	Rsd *rsd;
183abfa367dSDavid du Colombier 
184abfa367dSDavid du Colombier 	dprint("ACPI...");
185*00a4193cSDavid du Colombier 	if((rsd = sigsearch("RSD PTR ")) == nil) {
186abfa367dSDavid du Colombier 		dprint("none\n");
187abfa367dSDavid du Colombier 		return;
188abfa367dSDavid du Colombier 	}
189abfa367dSDavid du Colombier 
190abfa367dSDavid du Colombier 	dprint("rsd %#p physaddr %#ux length %ud %#llux rev %d oem %.6s\n",
191abfa367dSDavid du Colombier 		rsd, L32GET(rsd->raddr), L32GET(rsd->length),
192abfa367dSDavid du Colombier 		l64get(rsd->xaddr), rsd->revision, (char*)rsd->oemid);
193abfa367dSDavid du Colombier 
194abfa367dSDavid du Colombier 	if(rsd->revision == 2){
195abfa367dSDavid du Colombier 		if(mpacpirsdchecksum(rsd, 36) == nil)
196abfa367dSDavid du Colombier 			return;
197abfa367dSDavid du Colombier 		asize = 8;
198abfa367dSDavid du Colombier 		sdtpa = l64get(rsd->xaddr);
199abfa367dSDavid du Colombier 	} else {
200abfa367dSDavid du Colombier 		if(mpacpirsdchecksum(rsd, 20) == nil)
201abfa367dSDavid du Colombier 			return;
202abfa367dSDavid du Colombier 		asize = 4;
203abfa367dSDavid du Colombier 		sdtpa = L32GET(rsd->raddr);
204abfa367dSDavid du Colombier 	}
205abfa367dSDavid du Colombier 
206abfa367dSDavid du Colombier 	if((sdt = vmap(sdtpa, 8)) == nil)
207abfa367dSDavid du Colombier 		return;
208abfa367dSDavid du Colombier 	if((sdt[0] != 'R' && sdt[0] != 'X') || memcmp(sdt+1, "SDT", 3) != 0){
209abfa367dSDavid du Colombier 		vunmap(sdt, 8);
210abfa367dSDavid du Colombier 		return;
211abfa367dSDavid du Colombier 	}
212abfa367dSDavid du Colombier 	sdtlen = L32GET(sdt + 4);
213abfa367dSDavid du Colombier 	vunmap(sdt, 8);
214abfa367dSDavid du Colombier 
215abfa367dSDavid du Colombier 	if((sdt = vmap(sdtpa, sdtlen)) == nil)
216abfa367dSDavid du Colombier 		return;
217abfa367dSDavid du Colombier 	if(mpacpirsdchecksum(sdt, sdtlen) != nil)
218abfa367dSDavid du Colombier 		for(i = 36; i < sdtlen; i += asize){
219abfa367dSDavid du Colombier 			if(asize == 8)
220abfa367dSDavid du Colombier 				dhpa = l64get(sdt+i);
221abfa367dSDavid du Colombier 			else
222abfa367dSDavid du Colombier 				dhpa = L32GET(sdt+i);
223abfa367dSDavid du Colombier 
224abfa367dSDavid du Colombier 			if((tbl = vmap(dhpa, 8)) == nil)
225abfa367dSDavid du Colombier 				continue;
226abfa367dSDavid du Colombier 			tbllen = L32GET(tbl + 4);
227abfa367dSDavid du Colombier 			vunmap(tbl, 8);
228abfa367dSDavid du Colombier 
229abfa367dSDavid du Colombier 			if((tbl = vmap(dhpa, tbllen)) == nil)
230abfa367dSDavid du Colombier 				continue;
231abfa367dSDavid du Colombier 			if(mpacpirsdchecksum(tbl, tbllen) != nil)
232abfa367dSDavid du Colombier 				(*func)(tbl);
233abfa367dSDavid du Colombier 			vunmap(tbl, tbllen);
234abfa367dSDavid du Colombier 		}
235abfa367dSDavid du Colombier 	vunmap(sdt, sdtlen);
236abfa367dSDavid du Colombier }
237abfa367dSDavid du Colombier 
238abfa367dSDavid du Colombier static void
mpacpitbl(uchar * p)239abfa367dSDavid du Colombier mpacpitbl(uchar *p)
240abfa367dSDavid du Colombier {
241abfa367dSDavid du Colombier 	/* for now, just activate any idle cpus */
242abfa367dSDavid du Colombier 	if (memcmp(p, "APIC", 4) == 0)
243abfa367dSDavid du Colombier 		mpacpicpus((Madt *)p);
244abfa367dSDavid du Colombier }
245abfa367dSDavid du Colombier 
246abfa367dSDavid du Colombier static void
mpacpi(void)247abfa367dSDavid du Colombier mpacpi(void)
248abfa367dSDavid du Colombier {
249abfa367dSDavid du Colombier 	mpdebug = getconf("*debugmp") != nil;
250abfa367dSDavid du Colombier 	mpacpiscan(mpacpitbl);
251abfa367dSDavid du Colombier }
252abfa367dSDavid du Colombier 
253abfa367dSDavid du Colombier void	(*mpacpifunc)(void) = mpacpi;
254