xref: /plan9-contrib/sys/src/9k/k10/apic.c (revision 9ef1f84b659abcb917c5c090acbce0772e494f21)
1*9ef1f84bSDavid du Colombier #include "u.h"
2*9ef1f84bSDavid du Colombier #include "../port/lib.h"
3*9ef1f84bSDavid du Colombier #include "mem.h"
4*9ef1f84bSDavid du Colombier #include "dat.h"
5*9ef1f84bSDavid du Colombier #include "fns.h"
6*9ef1f84bSDavid du Colombier 
7*9ef1f84bSDavid du Colombier #include "apic.h"
8*9ef1f84bSDavid du Colombier #include "io.h"
9*9ef1f84bSDavid du Colombier 
10*9ef1f84bSDavid du Colombier enum {						/* Local APIC registers */
11*9ef1f84bSDavid du Colombier 	Id		= 0x0020,		/* Identification */
12*9ef1f84bSDavid du Colombier 	Ver		= 0x0030,		/* Version */
13*9ef1f84bSDavid du Colombier 	Tp		= 0x0080,		/* Task Priority */
14*9ef1f84bSDavid du Colombier 	Ap		= 0x0090,		/* Arbitration Priority */
15*9ef1f84bSDavid du Colombier 	Pp		= 0x00a0,		/* Processor Priority */
16*9ef1f84bSDavid du Colombier 	Eoi		= 0x00b0,		/* EOI */
17*9ef1f84bSDavid du Colombier 	Ld		= 0x00d0,		/* Logical Destination */
18*9ef1f84bSDavid du Colombier 	Df		= 0x00e0,		/* Destination Format */
19*9ef1f84bSDavid du Colombier 	Siv		= 0x00f0,		/* Spurious Interrupt Vector */
20*9ef1f84bSDavid du Colombier 	Is		= 0x0100,		/* Interrupt Status (8) */
21*9ef1f84bSDavid du Colombier 	Tm		= 0x0180,		/* Trigger Mode (8) */
22*9ef1f84bSDavid du Colombier 	Ir		= 0x0200,		/* Interrupt Request (8) */
23*9ef1f84bSDavid du Colombier 	Es		= 0x0280,		/* Error Status */
24*9ef1f84bSDavid du Colombier 	Iclo		= 0x0300,		/* Interrupt Command */
25*9ef1f84bSDavid du Colombier 	Ichi		= 0x0310,		/* Interrupt Command [63:32] */
26*9ef1f84bSDavid du Colombier 	Lvt0		= 0x0320,		/* Local Vector Table 0 */
27*9ef1f84bSDavid du Colombier 	Lvt5		= 0x0330,		/* Local Vector Table 5 */
28*9ef1f84bSDavid du Colombier 	Lvt4		= 0x0340,		/* Local Vector Table 4 */
29*9ef1f84bSDavid du Colombier 	Lvt1		= 0x0350,		/* Local Vector Table 1 */
30*9ef1f84bSDavid du Colombier 	Lvt2		= 0x0360,		/* Local Vector Table 2 */
31*9ef1f84bSDavid du Colombier 	Lvt3		= 0x0370,		/* Local Vector Table 3 */
32*9ef1f84bSDavid du Colombier 	Tic		= 0x0380,		/* Timer Initial Count */
33*9ef1f84bSDavid du Colombier 	Tcc		= 0x0390,		/* Timer Current Count */
34*9ef1f84bSDavid du Colombier 	Tdc		= 0x03e0,		/* Timer Divide Configuration */
35*9ef1f84bSDavid du Colombier 
36*9ef1f84bSDavid du Colombier 	Tlvt		= Lvt0,			/* Timer */
37*9ef1f84bSDavid du Colombier 	Lint0		= Lvt1,			/* Local Interrupt 0 */
38*9ef1f84bSDavid du Colombier 	Lint1		= Lvt2,			/* Local Interrupt 1 */
39*9ef1f84bSDavid du Colombier 	Elvt		= Lvt3,			/* Error */
40*9ef1f84bSDavid du Colombier 	Pmclvt		= Lvt4,			/* Performance Mon. Counter */
41*9ef1f84bSDavid du Colombier 	Thslvt		= Lvt5,			/* Thermal Sensor */
42*9ef1f84bSDavid du Colombier };
43*9ef1f84bSDavid du Colombier 
44*9ef1f84bSDavid du Colombier enum {						/* Siv */
45*9ef1f84bSDavid du Colombier 	Swen		= 0x00000100,		/* Software Enable */
46*9ef1f84bSDavid du Colombier 	Fdis		= 0x00000200,		/* Focus Disable */
47*9ef1f84bSDavid du Colombier };
48*9ef1f84bSDavid du Colombier 
49*9ef1f84bSDavid du Colombier enum {						/* Iclo */
50*9ef1f84bSDavid du Colombier 	Lassert		= 0x00004000,		/* Assert level */
51*9ef1f84bSDavid du Colombier 
52*9ef1f84bSDavid du Colombier 	DSnone		= 0x00000000,		/* Use Destination Field */
53*9ef1f84bSDavid du Colombier 	DSself		= 0x00040000,		/* Self is only destination */
54*9ef1f84bSDavid du Colombier 	DSallinc	= 0x00080000,		/* All including self */
55*9ef1f84bSDavid du Colombier 	DSallexc	= 0x000c0000,		/* All Excluding self */
56*9ef1f84bSDavid du Colombier };
57*9ef1f84bSDavid du Colombier 
58*9ef1f84bSDavid du Colombier enum {						/* Tlvt */
59*9ef1f84bSDavid du Colombier 	Periodic	= 0x00020000,		/* Periodic Timer Mode */
60*9ef1f84bSDavid du Colombier };
61*9ef1f84bSDavid du Colombier 
62*9ef1f84bSDavid du Colombier enum {						/* Tdc */
63*9ef1f84bSDavid du Colombier 	DivX2		= 0x00000000,		/* Divide by 2 */
64*9ef1f84bSDavid du Colombier 	DivX4		= 0x00000001,		/* Divide by 4 */
65*9ef1f84bSDavid du Colombier 	DivX8		= 0x00000002,		/* Divide by 8 */
66*9ef1f84bSDavid du Colombier 	DivX16		= 0x00000003,		/* Divide by 16 */
67*9ef1f84bSDavid du Colombier 	DivX32		= 0x00000008,		/* Divide by 32 */
68*9ef1f84bSDavid du Colombier 	DivX64		= 0x00000009,		/* Divide by 64 */
69*9ef1f84bSDavid du Colombier 	DivX128		= 0x0000000a,		/* Divide by 128 */
70*9ef1f84bSDavid du Colombier 	DivX1		= 0x0000000b,		/* Divide by 1 */
71*9ef1f84bSDavid du Colombier };
72*9ef1f84bSDavid du Colombier 
73*9ef1f84bSDavid du Colombier static u8int* apicbase;
74*9ef1f84bSDavid du Colombier 
75*9ef1f84bSDavid du Colombier static u32int
apicrget(int r)76*9ef1f84bSDavid du Colombier apicrget(int r)
77*9ef1f84bSDavid du Colombier {
78*9ef1f84bSDavid du Colombier 	return *((u32int*)(apicbase+r));
79*9ef1f84bSDavid du Colombier }
80*9ef1f84bSDavid du Colombier 
81*9ef1f84bSDavid du Colombier static void
apicrput(int r,u32int data)82*9ef1f84bSDavid du Colombier apicrput(int r, u32int data)
83*9ef1f84bSDavid du Colombier {
84*9ef1f84bSDavid du Colombier 	*((u32int*)(apicbase+r)) = data;
85*9ef1f84bSDavid du Colombier }
86*9ef1f84bSDavid du Colombier 
87*9ef1f84bSDavid du Colombier void
apictprput(int priority)88*9ef1f84bSDavid du Colombier apictprput(int priority)
89*9ef1f84bSDavid du Colombier {
90*9ef1f84bSDavid du Colombier 	apicrput(Tp, priority);
91*9ef1f84bSDavid du Colombier }
92*9ef1f84bSDavid du Colombier 
93*9ef1f84bSDavid du Colombier int
apiceoi(int vecno)94*9ef1f84bSDavid du Colombier apiceoi(int vecno)
95*9ef1f84bSDavid du Colombier {
96*9ef1f84bSDavid du Colombier 	apicrput(Eoi, 0);
97*9ef1f84bSDavid du Colombier 
98*9ef1f84bSDavid du Colombier 	return vecno;
99*9ef1f84bSDavid du Colombier }
100*9ef1f84bSDavid du Colombier 
101*9ef1f84bSDavid du Colombier int
apicisr(int vecno)102*9ef1f84bSDavid du Colombier apicisr(int vecno)
103*9ef1f84bSDavid du Colombier {
104*9ef1f84bSDavid du Colombier 	int isr;
105*9ef1f84bSDavid du Colombier 
106*9ef1f84bSDavid du Colombier 	isr = apicrget(Is + (vecno/32)*16);
107*9ef1f84bSDavid du Colombier 
108*9ef1f84bSDavid du Colombier 	return isr & (1<<(vecno%32));
109*9ef1f84bSDavid du Colombier }
110*9ef1f84bSDavid du Colombier 
111*9ef1f84bSDavid du Colombier void
apicinit(int apicno,uintmem pa,int isbp)112*9ef1f84bSDavid du Colombier apicinit(int apicno, uintmem pa, int isbp)
113*9ef1f84bSDavid du Colombier {
114*9ef1f84bSDavid du Colombier 	Apic *apic;
115*9ef1f84bSDavid du Colombier 
116*9ef1f84bSDavid du Colombier 	/*
117*9ef1f84bSDavid du Colombier 	 * Mark the APIC useable if it has a good ID
118*9ef1f84bSDavid du Colombier 	 * and the registers can be mapped.
119*9ef1f84bSDavid du Colombier 	 * The APIC Extended Broadcast and ID bits in the HyperTransport
120*9ef1f84bSDavid du Colombier 	 * Transaction Control register determine whether 4 or 8 bits
121*9ef1f84bSDavid du Colombier 	 * are used for the APIC ID. There is also xAPIC and x2APIC
122*9ef1f84bSDavid du Colombier 	 * to be dealt with sometime.
123*9ef1f84bSDavid du Colombier 	 */
124*9ef1f84bSDavid du Colombier 	DBG("apic%d: pa %#P isbp %d\n", apicno, pa, isbp);
125*9ef1f84bSDavid du Colombier 	if(apicno >= Napic){
126*9ef1f84bSDavid du Colombier 		print("apic%d: out of range\n", apicno);
127*9ef1f84bSDavid du Colombier 		return;
128*9ef1f84bSDavid du Colombier 	}
129*9ef1f84bSDavid du Colombier 	if((apic = &xapic[apicno])->useable){
130*9ef1f84bSDavid du Colombier 		print("apicinit%d: already initialised\n", apicno);
131*9ef1f84bSDavid du Colombier 		return;
132*9ef1f84bSDavid du Colombier 	}
133*9ef1f84bSDavid du Colombier 	if(apicbase == nil){
134*9ef1f84bSDavid du Colombier 		if((apicbase = vmap(pa, 1024)) == nil){
135*9ef1f84bSDavid du Colombier 			print("apic%d: can't map apicbase\n", apicno);
136*9ef1f84bSDavid du Colombier 			return;
137*9ef1f84bSDavid du Colombier 		}
138*9ef1f84bSDavid du Colombier 		DBG("apic%d: apicbase %#P -> %#p\n", apicno, pa, apicbase);
139*9ef1f84bSDavid du Colombier 	}
140*9ef1f84bSDavid du Colombier 	apic->useable = 1;
141*9ef1f84bSDavid du Colombier 
142*9ef1f84bSDavid du Colombier 	/*
143*9ef1f84bSDavid du Colombier 	 * Assign a machno to the processor associated with this
144*9ef1f84bSDavid du Colombier 	 * APIC, it may not be an identity map.
145*9ef1f84bSDavid du Colombier 	 * Machno 0 is always the bootstrap processor.
146*9ef1f84bSDavid du Colombier 	 */
147*9ef1f84bSDavid du Colombier 	if(isbp){
148*9ef1f84bSDavid du Colombier 		apic->machno = 0;
149*9ef1f84bSDavid du Colombier 		m->apicno = apicno;
150*9ef1f84bSDavid du Colombier 	}
151*9ef1f84bSDavid du Colombier 	else
152*9ef1f84bSDavid du Colombier 		apic->machno = sys->nmach++;
153*9ef1f84bSDavid du Colombier }
154*9ef1f84bSDavid du Colombier 
155*9ef1f84bSDavid du Colombier void
apicdump(void)156*9ef1f84bSDavid du Colombier apicdump(void)
157*9ef1f84bSDavid du Colombier {
158*9ef1f84bSDavid du Colombier 	int i;
159*9ef1f84bSDavid du Colombier 	Apic *apic;
160*9ef1f84bSDavid du Colombier 
161*9ef1f84bSDavid du Colombier 	if(!DBGFLG)
162*9ef1f84bSDavid du Colombier 		return;
163*9ef1f84bSDavid du Colombier 
164*9ef1f84bSDavid du Colombier 	DBG("apicbase %#p sys->nmach %d\n", apicbase, sys->nmach);
165*9ef1f84bSDavid du Colombier 	for(i = 0; i < Napic; i++){
166*9ef1f84bSDavid du Colombier 		apic = &xapic[i];
167*9ef1f84bSDavid du Colombier 		if(!apic->useable || apic->addr != 0)
168*9ef1f84bSDavid du Colombier 			continue;
169*9ef1f84bSDavid du Colombier 		DBG("apic%d: machno %d lint0 %#8.8ux lint1 %#8.8ux\n",
170*9ef1f84bSDavid du Colombier 			i, apic->machno, apic->lvt[0], apic->lvt[1]);
171*9ef1f84bSDavid du Colombier 		DBG(" thslvt %#8.8ux pmclvt %#8.8ux elvt %#8.8ux\n",
172*9ef1f84bSDavid du Colombier 			apicrget(Thslvt), apicrget(Pmclvt), apicrget(Elvt));
173*9ef1f84bSDavid du Colombier 		DBG(" tlvt %#8.8ux lint0 %#8.8ux lint1 %#8.8ux siv %#8.8ux\n",
174*9ef1f84bSDavid du Colombier 			apicrget(Tlvt), apicrget(Lint0),
175*9ef1f84bSDavid du Colombier 			apicrget(Lint1), apicrget(Siv));
176*9ef1f84bSDavid du Colombier 	}
177*9ef1f84bSDavid du Colombier }
178*9ef1f84bSDavid du Colombier 
179*9ef1f84bSDavid du Colombier int
apiconline(void)180*9ef1f84bSDavid du Colombier apiconline(void)
181*9ef1f84bSDavid du Colombier {
182*9ef1f84bSDavid du Colombier 	Apic *apic;
183*9ef1f84bSDavid du Colombier 	u64int tsc;
184*9ef1f84bSDavid du Colombier 	u32int dfr, ver;
185*9ef1f84bSDavid du Colombier 	int apicno, nlvt;
186*9ef1f84bSDavid du Colombier 
187*9ef1f84bSDavid du Colombier 	if(apicbase == nil)
188*9ef1f84bSDavid du Colombier 		return 0;
189*9ef1f84bSDavid du Colombier 	if((apicno = ((apicrget(Id)>>24) & 0xff)) >= Napic)
190*9ef1f84bSDavid du Colombier 		return 0;
191*9ef1f84bSDavid du Colombier 	apic = &xapic[apicno];
192*9ef1f84bSDavid du Colombier 	if(!apic->useable || apic->addr != nil)
193*9ef1f84bSDavid du Colombier 		return 0;
194*9ef1f84bSDavid du Colombier 
195*9ef1f84bSDavid du Colombier 	/*
196*9ef1f84bSDavid du Colombier 	 * Things that can only be done when on the processor
197*9ef1f84bSDavid du Colombier 	 * owning the APIC, apicinit above runs on the bootstrap
198*9ef1f84bSDavid du Colombier 	 * processor.
199*9ef1f84bSDavid du Colombier 	 */
200*9ef1f84bSDavid du Colombier 	ver = apicrget(Ver);
201*9ef1f84bSDavid du Colombier 	nlvt = ((ver>>16) & 0xff) + 1;
202*9ef1f84bSDavid du Colombier 	if(nlvt > nelem(apic->lvt)){
203*9ef1f84bSDavid du Colombier 		print("apicinit%d: nlvt %d > max (%d)\n",
204*9ef1f84bSDavid du Colombier 			apicno, nlvt, nelem(apic->lvt));
205*9ef1f84bSDavid du Colombier 		nlvt = nelem(apic->lvt);
206*9ef1f84bSDavid du Colombier 	}
207*9ef1f84bSDavid du Colombier 	apic->nlvt = nlvt;
208*9ef1f84bSDavid du Colombier 	apic->ver = ver & 0xff;
209*9ef1f84bSDavid du Colombier 
210*9ef1f84bSDavid du Colombier 	/*
211*9ef1f84bSDavid du Colombier 	 * These don't really matter in Physical mode;
212*9ef1f84bSDavid du Colombier 	 * set the defaults anyway.
213*9ef1f84bSDavid du Colombier 	 */
214*9ef1f84bSDavid du Colombier 	if(memcmp(&m->cpuinfo[0][1], "AuthenticAMD", 12) == 0)
215*9ef1f84bSDavid du Colombier 		dfr = 0xf0000000;
216*9ef1f84bSDavid du Colombier 	else
217*9ef1f84bSDavid du Colombier 		dfr = 0xffffffff;
218*9ef1f84bSDavid du Colombier 	apicrput(Df, dfr);
219*9ef1f84bSDavid du Colombier 	apicrput(Ld, 0x00000000);
220*9ef1f84bSDavid du Colombier 
221*9ef1f84bSDavid du Colombier 	/*
222*9ef1f84bSDavid du Colombier 	 * Disable interrupts until ready by setting the Task Priority
223*9ef1f84bSDavid du Colombier 	 * register to 0xff.
224*9ef1f84bSDavid du Colombier 	 */
225*9ef1f84bSDavid du Colombier 	apicrput(Tp, 0xff);
226*9ef1f84bSDavid du Colombier 
227*9ef1f84bSDavid du Colombier 	/*
228*9ef1f84bSDavid du Colombier 	 * Software-enable the APIC in the Spurious Interrupt Vector
229*9ef1f84bSDavid du Colombier 	 * register and set the vector number. The vector number must have
230*9ef1f84bSDavid du Colombier 	 * bits 3-0 0x0f unless the Extended Spurious Vector Enable bit
231*9ef1f84bSDavid du Colombier 	 * is set in the HyperTransport Transaction Control register.
232*9ef1f84bSDavid du Colombier 	 */
233*9ef1f84bSDavid du Colombier 	apicrput(Siv, Swen|IdtSPURIOUS);
234*9ef1f84bSDavid du Colombier 
235*9ef1f84bSDavid du Colombier 	/*
236*9ef1f84bSDavid du Colombier 	 * Acknowledge any outstanding interrupts.
237*9ef1f84bSDavid du Colombier 	 */
238*9ef1f84bSDavid du Colombier 	apicrput(Eoi, 0);
239*9ef1f84bSDavid du Colombier 
240*9ef1f84bSDavid du Colombier 	/*
241*9ef1f84bSDavid du Colombier 	 * Use the TSC to determine the APIC timer frequency.
242*9ef1f84bSDavid du Colombier 	 * It might be possible to snarf this from a chipset
243*9ef1f84bSDavid du Colombier 	 * register instead.
244*9ef1f84bSDavid du Colombier 	 */
245*9ef1f84bSDavid du Colombier 	apicrput(Tdc, DivX1);
246*9ef1f84bSDavid du Colombier 	apicrput(Tlvt, Im|IdtTIMER);
247*9ef1f84bSDavid du Colombier 	tsc = rdtsc() + m->cpuhz/10;
248*9ef1f84bSDavid du Colombier 	apicrput(Tic, 0xffffffff);
249*9ef1f84bSDavid du Colombier 
250*9ef1f84bSDavid du Colombier 	while(rdtsc() < tsc)
251*9ef1f84bSDavid du Colombier 		;
252*9ef1f84bSDavid du Colombier 
253*9ef1f84bSDavid du Colombier 	apic->hz = (0xffffffff-apicrget(Tcc))*10;
254*9ef1f84bSDavid du Colombier 	apic->max = apic->hz/HZ;
255*9ef1f84bSDavid du Colombier 	apic->min = apic->hz/(100*HZ);
256*9ef1f84bSDavid du Colombier 	apic->div = ((m->cpuhz/apic->max)+HZ/2)/HZ;
257*9ef1f84bSDavid du Colombier 
258*9ef1f84bSDavid du Colombier 	if(m->machno == 0 || DBGFLG){
259*9ef1f84bSDavid du Colombier 		print("apic%d: hz %lld max %lld min %lld div %lld\n", apicno,
260*9ef1f84bSDavid du Colombier 			apic->hz, apic->max, apic->min, apic->div);
261*9ef1f84bSDavid du Colombier 	}
262*9ef1f84bSDavid du Colombier 
263*9ef1f84bSDavid du Colombier 	/*
264*9ef1f84bSDavid du Colombier 	 * Mask interrupts on Performance Monitor Counter overflow and
265*9ef1f84bSDavid du Colombier 	 * Thermal Sensor if implemented, and on Lintr0 (Legacy INTR),
266*9ef1f84bSDavid du Colombier 	 * and Lintr1 (Legacy NMI).
267*9ef1f84bSDavid du Colombier 	 * Clear any Error Status (write followed by read) and enable
268*9ef1f84bSDavid du Colombier 	 * the Error interrupt.
269*9ef1f84bSDavid du Colombier 	 */
270*9ef1f84bSDavid du Colombier 	switch(apic->nlvt){
271*9ef1f84bSDavid du Colombier 	case 6:
272*9ef1f84bSDavid du Colombier 		apicrput(Thslvt, Im|IdtTHS);
273*9ef1f84bSDavid du Colombier 		/*FALLTHROUGH*/
274*9ef1f84bSDavid du Colombier 	case 5:
275*9ef1f84bSDavid du Colombier 		apicrput(Pmclvt, Im|IdtPMC);
276*9ef1f84bSDavid du Colombier 		/*FALLTHROUGH*/
277*9ef1f84bSDavid du Colombier 	default:
278*9ef1f84bSDavid du Colombier 		break;
279*9ef1f84bSDavid du Colombier 	}
280*9ef1f84bSDavid du Colombier 	apicrput(Lint1, apic->lvt[1]|Im|IdtLINT1);
281*9ef1f84bSDavid du Colombier 	apicrput(Lint0, apic->lvt[0]|Im|IdtLINT0);
282*9ef1f84bSDavid du Colombier 
283*9ef1f84bSDavid du Colombier 	apicrput(Es, 0);
284*9ef1f84bSDavid du Colombier 	apicrget(Es);
285*9ef1f84bSDavid du Colombier 	apicrput(Elvt, IdtERROR);
286*9ef1f84bSDavid du Colombier 
287*9ef1f84bSDavid du Colombier 	/*
288*9ef1f84bSDavid du Colombier 	 * Issue an INIT Level De-Assert to synchronise arbitration ID's.
289*9ef1f84bSDavid du Colombier 	 * (Necessary in this implementation? - not if Pentium 4 or Xeon
290*9ef1f84bSDavid du Colombier 	 * (APIC Version >= 0x14), or AMD).
291*9ef1f84bSDavid du Colombier 	apicrput(Ichi, 0);
292*9ef1f84bSDavid du Colombier 	apicrput(Iclo, DSallinc|Lassert|MTir);
293*9ef1f84bSDavid du Colombier 	while(apicrget(Iclo) & Ds)
294*9ef1f84bSDavid du Colombier 		;
295*9ef1f84bSDavid du Colombier 	 */
296*9ef1f84bSDavid du Colombier 
297*9ef1f84bSDavid du Colombier 	/*
298*9ef1f84bSDavid du Colombier 	 * Reload the timer to de-synchronise the processors.
299*9ef1f84bSDavid du Colombier 	 * When the caller is ready for the APIC to accept interrupts,
300*9ef1f84bSDavid du Colombier 	 * it should call apictprput to lower the task priority.
301*9ef1f84bSDavid du Colombier 	 *
302*9ef1f84bSDavid du Colombier 	 * The timer is enabled later by the core-specific startup
303*9ef1f84bSDavid du Colombier 	 * i.e. don't start the timer unless the core needs it,
304*9ef1f84bSDavid du Colombier 	 * to reduce the likelihood of at least one (spurious) interrupt
305*9ef1f84bSDavid du Colombier 	 * from the timer when priority is lowered.
306*9ef1f84bSDavid du Colombier 	 */
307*9ef1f84bSDavid du Colombier 	microdelay((TK2MS(1)*1000/sys->nmach) * m->machno);
308*9ef1f84bSDavid du Colombier 	apicrput(Tic, apic->max);
309*9ef1f84bSDavid du Colombier 
310*9ef1f84bSDavid du Colombier 	return 1;
311*9ef1f84bSDavid du Colombier }
312*9ef1f84bSDavid du Colombier 
313*9ef1f84bSDavid du Colombier void
apictimerenable(void)314*9ef1f84bSDavid du Colombier apictimerenable(void)
315*9ef1f84bSDavid du Colombier {
316*9ef1f84bSDavid du Colombier 	/*
317*9ef1f84bSDavid du Colombier 	 * Perhaps apictimerenable/apictimerdisable should just
318*9ef1f84bSDavid du Colombier 	 * clear/set Im in the existing settings of Tlvt, there may
319*9ef1f84bSDavid du Colombier 	 * be a time when the timer is used in a different mode;
320*9ef1f84bSDavid du Colombier 	 * if so will need to ensure the mode is set when the timer
321*9ef1f84bSDavid du Colombier 	 * is initialised.
322*9ef1f84bSDavid du Colombier 	 */
323*9ef1f84bSDavid du Colombier 	apicrput(Tlvt, Periodic|IdtTIMER);
324*9ef1f84bSDavid du Colombier }
325*9ef1f84bSDavid du Colombier 
326*9ef1f84bSDavid du Colombier void
apictimerdisable(void)327*9ef1f84bSDavid du Colombier apictimerdisable(void)
328*9ef1f84bSDavid du Colombier {
329*9ef1f84bSDavid du Colombier 	apicrput(Tlvt, Im|IdtTIMER);
330*9ef1f84bSDavid du Colombier }
331*9ef1f84bSDavid du Colombier 
332*9ef1f84bSDavid du Colombier void
apictimerset(uvlong next)333*9ef1f84bSDavid du Colombier apictimerset(uvlong next)
334*9ef1f84bSDavid du Colombier {
335*9ef1f84bSDavid du Colombier 	Mpl pl;
336*9ef1f84bSDavid du Colombier 	Apic *apic;
337*9ef1f84bSDavid du Colombier 	vlong period;
338*9ef1f84bSDavid du Colombier 
339*9ef1f84bSDavid du Colombier 	/*
340*9ef1f84bSDavid du Colombier 	 * APIC Timer.
341*9ef1f84bSDavid du Colombier 	 */
342*9ef1f84bSDavid du Colombier 	apic = &xapic[m->apicno];
343*9ef1f84bSDavid du Colombier 
344*9ef1f84bSDavid du Colombier 	pl = splhi();
345*9ef1f84bSDavid du Colombier 	lock(&m->apictimerlock);
346*9ef1f84bSDavid du Colombier 
347*9ef1f84bSDavid du Colombier 	period = apic->max;
348*9ef1f84bSDavid du Colombier 	if(next != 0){
349*9ef1f84bSDavid du Colombier 		period = next - fastticks(nil);	/* fastticks is just rdtsc() */
350*9ef1f84bSDavid du Colombier 		period /= apic->div;
351*9ef1f84bSDavid du Colombier 
352*9ef1f84bSDavid du Colombier 		if(period < apic->min)
353*9ef1f84bSDavid du Colombier 			period = apic->min;
354*9ef1f84bSDavid du Colombier 		else if(period > apic->max - apic->min)
355*9ef1f84bSDavid du Colombier 			period = apic->max;
356*9ef1f84bSDavid du Colombier 	}
357*9ef1f84bSDavid du Colombier 	apicrput(Tic, period);
358*9ef1f84bSDavid du Colombier 
359*9ef1f84bSDavid du Colombier 	unlock(&m->apictimerlock);
360*9ef1f84bSDavid du Colombier 	splx(pl);
361*9ef1f84bSDavid du Colombier }
362*9ef1f84bSDavid du Colombier 
363*9ef1f84bSDavid du Colombier void
apictimerintr(Ureg * ureg,void *)364*9ef1f84bSDavid du Colombier apictimerintr(Ureg* ureg, void*)
365*9ef1f84bSDavid du Colombier {
366*9ef1f84bSDavid du Colombier 	timerintr(ureg, 0);
367*9ef1f84bSDavid du Colombier }
368*9ef1f84bSDavid du Colombier 
369*9ef1f84bSDavid du Colombier void
apicsipi(int apicno,uintptr pa)370*9ef1f84bSDavid du Colombier apicsipi(int apicno, uintptr pa)
371*9ef1f84bSDavid du Colombier {
372*9ef1f84bSDavid du Colombier 	int i;
373*9ef1f84bSDavid du Colombier 	u32int crhi, crlo;
374*9ef1f84bSDavid du Colombier 
375*9ef1f84bSDavid du Colombier 	/*
376*9ef1f84bSDavid du Colombier 	 * SIPI - Start-up IPI.
377*9ef1f84bSDavid du Colombier 	 * To do: checks on apic validity.
378*9ef1f84bSDavid du Colombier 	 */
379*9ef1f84bSDavid du Colombier 	crhi = apicno<<24;
380*9ef1f84bSDavid du Colombier 	apicrput(Ichi, crhi);
381*9ef1f84bSDavid du Colombier 	apicrput(Iclo, DSnone|TMlevel|Lassert|MTir);
382*9ef1f84bSDavid du Colombier 	microdelay(200);
383*9ef1f84bSDavid du Colombier 	apicrput(Iclo, DSnone|TMlevel|MTir);
384*9ef1f84bSDavid du Colombier 	millidelay(10);
385*9ef1f84bSDavid du Colombier 
386*9ef1f84bSDavid du Colombier 	crlo = DSnone|TMedge|MTsipi|((u32int)pa/(4*KiB));
387*9ef1f84bSDavid du Colombier 	for(i = 0; i < 2; i++){
388*9ef1f84bSDavid du Colombier 		apicrput(Ichi, crhi);
389*9ef1f84bSDavid du Colombier 		apicrput(Iclo, crlo);
390*9ef1f84bSDavid du Colombier 		microdelay(200);
391*9ef1f84bSDavid du Colombier 	}
392*9ef1f84bSDavid du Colombier }
393*9ef1f84bSDavid du Colombier 
394*9ef1f84bSDavid du Colombier void
apicipi(int apicno)395*9ef1f84bSDavid du Colombier apicipi(int apicno)
396*9ef1f84bSDavid du Colombier {
397*9ef1f84bSDavid du Colombier 	apicrput(Ichi, apicno<<24);
398*9ef1f84bSDavid du Colombier 	apicrput(Iclo, DSnone|TMedge|Lassert|MTf|IdtIPI);
399*9ef1f84bSDavid du Colombier 	while(apicrget(Iclo) & Ds)
400*9ef1f84bSDavid du Colombier 		;
401*9ef1f84bSDavid du Colombier }
402