Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
 
8
#include "mp.h"
9
 
10
enum {					/* Local APIC registers */
11
	LapicID		= 0x0020,	/* ID */
12
	LapicVER	= 0x0030,	/* Version */
13
	LapicTPR	= 0x0080,	/* Task Priority */
14
	LapicAPR	= 0x0090,	/* Arbitration Priority */
15
	LapicPPR	= 0x00A0,	/* Processor Priority */
16
	LapicEOI	= 0x00B0,	/* EOI */
17
	LapicLDR	= 0x00D0,	/* Logical Destination */
18
	LapicDFR	= 0x00E0,	/* Destination Format */
19
	LapicSVR	= 0x00F0,	/* Spurious Interrupt Vector */
20
	LapicISR	= 0x0100,	/* Interrupt Status (8 registers) */
21
	LapicTMR	= 0x0180,	/* Trigger Mode (8 registers) */
22
	LapicIRR	= 0x0200,	/* Interrupt Request (8 registers) */
23
	LapicESR	= 0x0280,	/* Error Status */
24
	LapicICRLO	= 0x0300,	/* Interrupt Command */
25
	LapicICRHI	= 0x0310,	/* Interrupt Command [63:32] */
26
	LapicTIMER	= 0x0320,	/* Local Vector Table 0 (TIMER) */
27
	LapicPCINT	= 0x0340,	/* Performance Counter LVT */
28
	LapicLINT0	= 0x0350,	/* Local Vector Table 1 (LINT0) */
29
	LapicLINT1	= 0x0360,	/* Local Vector Table 2 (LINT1) */
30
	LapicERROR	= 0x0370,	/* Local Vector Table 3 (ERROR) */
31
	LapicTICR	= 0x0380,	/* Timer Initial Count */
32
	LapicTCCR	= 0x0390,	/* Timer Current Count */
33
	LapicTDCR	= 0x03E0,	/* Timer Divide Configuration */
34
};
35
 
36
enum {					/* LapicSVR */
37
	LapicENABLE	= 0x00000100,	/* Unit Enable */
38
	LapicFOCUS	= 0x00000200,	/* Focus Processor Checking Disable */
39
};
40
 
41
enum {					/* LapicICRLO */
42
					/* [14] IPI Trigger Mode Level (RW) */
43
	LapicDEASSERT	= 0x00000000,	/* Deassert level-sensitive interrupt */
44
	LapicASSERT	= 0x00004000,	/* Assert level-sensitive interrupt */
45
 
46
					/* [17:16] Remote Read Status */
47
	LapicINVALID	= 0x00000000,	/* Invalid */
48
	LapicWAIT	= 0x00010000,	/* In-Progress */
49
	LapicVALID	= 0x00020000,	/* Valid */
50
 
51
					/* [19:18] Destination Shorthand */
52
	LapicFIELD	= 0x00000000,	/* No shorthand */
53
	LapicSELF	= 0x00040000,	/* Self is single destination */
54
	LapicALLINC	= 0x00080000,	/* All including self */
55
	LapicALLEXC	= 0x000C0000,	/* All Excluding self */
56
};
57
 
58
enum {					/* LapicESR */
59
	LapicSENDCS	= 0x00000001,	/* Send CS Error */
60
	LapicRCVCS	= 0x00000002,	/* Receive CS Error */
61
	LapicSENDACCEPT	= 0x00000004,	/* Send Accept Error */
62
	LapicRCVACCEPT	= 0x00000008,	/* Receive Accept Error */
63
	LapicSENDVECTOR	= 0x00000020,	/* Send Illegal Vector */
64
	LapicRCVVECTOR	= 0x00000040,	/* Receive Illegal Vector */
65
	LapicREGISTER	= 0x00000080,	/* Illegal Register Address */
66
};
67
 
68
enum {					/* LapicTIMER */
69
					/* [17] Timer Mode (RW) */
70
	LapicONESHOT	= 0x00000000,	/* One-shot */
71
	LapicPERIODIC	= 0x00020000,	/* Periodic */
72
 
73
					/* [19:18] Timer Base (RW) */
74
	LapicCLKIN	= 0x00000000,	/* use CLKIN as input */
75
	LapicTMBASE	= 0x00040000,	/* use TMBASE */
76
	LapicDIVIDER	= 0x00080000,	/* use output of the divider */
77
};
78
 
79
enum {					/* LapicTDCR */
80
	LapicX2		= 0x00000000,	/* divide by 2 */
81
	LapicX4		= 0x00000001,	/* divide by 4 */
82
	LapicX8		= 0x00000002,	/* divide by 8 */
83
	LapicX16	= 0x00000003,	/* divide by 16 */
84
	LapicX32	= 0x00000008,	/* divide by 32 */
85
	LapicX64	= 0x00000009,	/* divide by 64 */
86
	LapicX128	= 0x0000000A,	/* divide by 128 */
87
	LapicX1		= 0x0000000B,	/* divide by 1 */
88
};
89
 
90
static ulong* lapicbase;
91
 
92
struct
93
{
94
	uvlong	hz;
95
	ulong	max;
96
	ulong	min;
97
	ulong	div;
98
} lapictimer;
99
 
100
static ulong
101
lapicr(int r)
102
{
103
	if(lapicbase == 0)
104
		panic("lapicr: no lapic");
105
	return *(lapicbase+(r/sizeof(*lapicbase)));
106
}
107
 
108
static void
109
lapicw(int r, ulong data)
110
{
111
	if(lapicbase == 0)
112
		panic("lapicw: no lapic");
113
	*(lapicbase+(r/sizeof(*lapicbase))) = data;
114
	data = *(lapicbase+(LapicID/sizeof(*lapicbase)));
115
	USED(data);
116
}
117
 
118
void
119
lapiconline(void)
120
{
121
	/*
122
	 * Reload the timer to de-synchronise the processors,
123
	 * then lower the task priority to allow interrupts to be
124
	 * accepted by the APIC.
125
	 */
126
	microdelay((TK2MS(1)*1000/conf.nmach) * m->machno);
127
	lapicw(LapicTICR, lapictimer.max);
128
	lapicw(LapicTIMER, LapicCLKIN|LapicPERIODIC|(VectorPIC+IrqTIMER));
129
 
130
	lapicw(LapicTPR, 0);
131
}
132
 
133
/*
134
 *  use the i8253 clock to figure out our lapic timer rate.
135
 */
136
static void
137
lapictimerinit(void)
138
{
139
	uvlong x, v, hz;
140
 
141
	v = m->cpuhz/1000;
142
	lapicw(LapicTDCR, LapicX1);
143
	lapicw(LapicTIMER, ApicIMASK|LapicCLKIN|LapicONESHOT|(VectorPIC+IrqTIMER));
144
 
145
	if(lapictimer.hz == 0ULL){
146
		x = fastticks(&hz);
147
		x += hz/10;
148
		lapicw(LapicTICR, 0xffffffff);
149
		do{
150
			v = fastticks(nil);
151
		}while(v < x);
152
 
153
		lapictimer.hz = (0xffffffffUL-lapicr(LapicTCCR))*10;
154
		lapictimer.max = lapictimer.hz/HZ;
155
		lapictimer.min = lapictimer.hz/(100*HZ);
156
 
157
		if(lapictimer.hz > hz-(hz/10)){
158
			if(lapictimer.hz > hz+(hz/10))
159
				panic("lapic clock %lld > cpu clock > %lld\n",
160
					lapictimer.hz, hz);
161
			lapictimer.hz = hz;
162
		}
163
		assert(lapictimer.hz != 0);
164
		lapictimer.div = hz/lapictimer.hz;
165
	}
166
}
167
 
168
void
169
lapicinit(Apic* apic)
170
{
171
	ulong dfr, ldr, lvt;
172
 
173
	if(lapicbase == 0)
174
		lapicbase = apic->addr;
175
	if(lapicbase == 0) {
176
		print("lapicinit: no lapic\n");
177
		return;
178
	}
179
 
180
	/*
181
	 * These don't really matter in Physical mode;
182
	 * set the defaults anyway.
183
	 */
184
	if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0)
185
		dfr = 0xf0000000;
186
	else
187
		dfr = 0xffffffff;
188
	ldr = 0x00000000;
189
 
190
	lapicw(LapicDFR, dfr);
191
	lapicw(LapicLDR, ldr);
192
	lapicw(LapicTPR, 0xff);
193
	lapicw(LapicSVR, LapicENABLE|(VectorPIC+IrqSPURIOUS));
194
 
195
	lapictimerinit();
196
 
197
	/*
198
	 * Some Pentium revisions have a bug whereby spurious
199
	 * interrupts are generated in the through-local mode.
200
	 */
201
	switch(m->cpuidax & 0xFFF){
202
	case 0x526:				/* stepping cB1 */
203
	case 0x52B:				/* stepping E0 */
204
	case 0x52C:				/* stepping cC0 */
205
		wrmsr(0x0E, 1<<14);		/* TR12 */
206
		break;
207
	}
208
 
209
	/*
210
	 * Set the local interrupts. It's likely these should just be
211
	 * masked off for SMP mode as some Pentium Pros have problems if
212
	 * LINT[01] are set to ExtINT.
213
	 * Acknowledge any outstanding interrupts.
214
	lapicw(LapicLINT0, apic->lintr[0]);
215
	lapicw(LapicLINT1, apic->lintr[1]);
216
	 */
217
	lapiceoi(0);
218
 
219
	lvt = (lapicr(LapicVER)>>16) & 0xFF;
220
	if(lvt >= 4)
221
		lapicw(LapicPCINT, ApicIMASK|(VectorPIC+IrqPCINT));
222
	lapicw(LapicERROR, VectorPIC+IrqERROR);
223
	lapicw(LapicESR, 0);
224
	lapicr(LapicESR);
225
 
226
	/*
227
	 * Issue an INIT Level De-Assert to synchronise arbitration ID's.
228
	 */
229
	lapicw(LapicICRHI, 0);
230
	lapicw(LapicICRLO, LapicALLINC|ApicLEVEL|LapicDEASSERT|ApicINIT);
231
	while(lapicr(LapicICRLO) & ApicDELIVS)
232
		;
233
 
234
	/*
235
	 * Do not allow acceptance of interrupts until all initialisation
236
	 * for this processor is done. For the bootstrap processor this can be
237
	 * early during initialisation. For the application processors this should
238
	 * be after the bootstrap processor has lowered priority and is accepting
239
	 * interrupts.
240
	lapicw(LapicTPR, 0);
241
	 */
242
}
243
 
244
void
245
lapicstartap(Apic* apic, int v)
246
{
247
	int i;
248
	ulong crhi;
249
 
250
	/* make apic's processor do a warm reset */
251
	crhi = apic->apicno<<24;
252
	lapicw(LapicICRHI, crhi);
253
	lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicASSERT|ApicINIT);
254
	microdelay(200);
255
	lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicDEASSERT|ApicINIT);
256
	delay(10);
257
 
258
	/* assumes apic is not an 82489dx */
259
	for(i = 0; i < 2; i++){
260
		lapicw(LapicICRHI, crhi);
261
		/* make apic's processor start at v in real mode */
262
		lapicw(LapicICRLO, LapicFIELD|ApicEDGE|ApicSTARTUP|(v/BY2PG));
263
		microdelay(200);
264
	}
265
}
266
 
267
void
268
lapicerror(Ureg*, void*)
269
{
270
	ulong esr;
271
 
272
	lapicw(LapicESR, 0);
273
	esr = lapicr(LapicESR);
274
	switch(m->cpuidax & 0xFFF){
275
	case 0x526:				/* stepping cB1 */
276
	case 0x52B:				/* stepping E0 */
277
	case 0x52C:				/* stepping cC0 */
278
		return;
279
	}
280
	print("cpu%d: lapicerror: 0x%8.8luX\n", m->machno, esr);
281
}
282
 
283
void
284
lapicspurious(Ureg*, void*)
285
{
286
	print("cpu%d: lapicspurious\n", m->machno);
287
}
288
 
289
int
290
lapicisr(int v)
291
{
292
	ulong isr;
293
 
294
	isr = lapicr(LapicISR + (v/32));
295
 
296
	return isr & (1<<(v%32));
297
}
298
 
299
int
300
lapiceoi(int v)
301
{
302
	lapicw(LapicEOI, 0);
303
 
304
	return v;
305
}
306
 
307
void
308
lapicicrw(ulong hi, ulong lo)
309
{
310
	lapicw(LapicICRHI, hi);
311
	lapicw(LapicICRLO, lo);
312
}
313
 
314
void
315
ioapicrdtr(Apic* apic, int sel, int* hi, int* lo)
316
{
317
	ulong *iowin;
318
 
319
	iowin = apic->addr+(0x10/sizeof(ulong));
320
	sel = IoapicRDT + 2*sel;
321
 
322
	lock(apic);
323
	*apic->addr = sel+1;
324
	if(hi)
325
		*hi = *iowin;
326
	*apic->addr = sel;
327
	if(lo)
328
		*lo = *iowin;
329
	unlock(apic);
330
}
331
 
332
void
333
ioapicrdtw(Apic* apic, int sel, int hi, int lo)
334
{
335
	ulong *iowin;
336
 
337
	iowin = apic->addr+(0x10/sizeof(ulong));
338
	sel = IoapicRDT + 2*sel;
339
 
340
	lock(apic);
341
	*apic->addr = sel+1;
342
	*iowin = hi;
343
	*apic->addr = sel;
344
	*iowin = lo;
345
	unlock(apic);
346
}
347
 
348
void
349
ioapicinit(Apic* apic, int apicno)
350
{
351
	int hi, lo, v;
352
	ulong *iowin;
353
 
354
	/*
355
	 * Initialise the I/O APIC.
356
	 * The MultiProcessor Specification says it is the responsibility
357
	 * of the O/S to set the APIC id.
358
	 * Make sure interrupts are all masked off for now.
359
	 */
360
	iowin = apic->addr+(0x10/sizeof(ulong));
361
	lock(apic);
362
	*apic->addr = IoapicVER;
363
	apic->mre = (*iowin>>16) & 0xFF;
364
 
365
	*apic->addr = IoapicID;
366
	*iowin = apicno<<24;
367
	unlock(apic);
368
 
369
	hi = 0;
370
	lo = ApicIMASK;
371
	for(v = 0; v <= apic->mre; v++)
372
		ioapicrdtw(apic, v, hi, lo);
373
}
374
 
375
void
376
lapictimerset(uvlong next)
377
{
378
	vlong period;
379
	int x;
380
 
381
	x = splhi();
382
	lock(&m->apictimerlock);
383
 
384
	period = lapictimer.max;
385
	if(next != 0){
386
		period = next - fastticks(nil);
387
		if (lapictimer.div == 0)
388
			panic("lapictimerset: zero lapictimer.div");
389
		period /= lapictimer.div;
390
 
391
		if(period < lapictimer.min)
392
			period = lapictimer.min;
393
		else if(period > lapictimer.max - lapictimer.min)
394
			period = lapictimer.max;
395
	}
396
	lapicw(LapicTICR, period);
397
 
398
	unlock(&m->apictimerlock);
399
	splx(x);
400
}
401
 
402
void
403
lapicclock(Ureg *u, void*)
404
{
405
	/*
406
	 * since the MTRR updates need to be synchronized across processors,
407
	 * we want to do this within the clock tick.
408
	 */
409
	mtrrclock();
410
	timerintr(u, 0);
411
}
412
 
413
void
414
lapicintron(void)
415
{
416
	lapicw(LapicTPR, 0);
417
}
418
 
419
void
420
lapicintroff(void)
421
{
422
	lapicw(LapicTPR, 0xFF);
423
}
424
 
425
void
426
lapicnmienable(void)
427
{
428
	/*
429
	 * On the one hand the manual says the vector information
430
	 * is ignored if the delivery mode is NMI, and on the other
431
	 * a "Receive Illegal Vector" should be generated for a
432
	 * vector in the range 0 through 15.
433
	 * Some implementations generate the error interrupt if the
434
	 * NMI vector is invalid, so always give a valid value.
435
	 */
436
	if (lapicbase)
437
		lapicw(LapicPCINT, ApicNMI|(VectorPIC+IrqPCINT));
438
	else
439
		print("lapicnmienable: no lapic\n");
440
}
441
 
442
void
443
lapicnmidisable(void)
444
{
445
	if (lapicbase)
446
		lapicw(LapicPCINT, ApicIMASK|(VectorPIC+IrqPCINT));
447
	else
448
		print("lapicnmidisable: no lapic\n");
449
}