xref: /plan9/sys/src/9/pc/apic.c (revision afaac077351c6c0d3d2dfc98c64b1a45ead81394)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "io.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier #include "mp.h"
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier enum {					/* Local APIC registers */
117dd7cddfSDavid du Colombier 	LapicID		= 0x0020,	/* ID */
127dd7cddfSDavid du Colombier 	LapicVER	= 0x0030,	/* Version */
137dd7cddfSDavid du Colombier 	LapicTPR	= 0x0080,	/* Task Priority */
147dd7cddfSDavid du Colombier 	LapicAPR	= 0x0090,	/* Arbitration Priority */
157dd7cddfSDavid du Colombier 	LapicPPR	= 0x00A0,	/* Processor Priority */
167dd7cddfSDavid du Colombier 	LapicEOI	= 0x00B0,	/* EOI */
177dd7cddfSDavid du Colombier 	LapicLDR	= 0x00D0,	/* Logical Destination */
187dd7cddfSDavid du Colombier 	LapicDFR	= 0x00E0,	/* Destination Format */
197dd7cddfSDavid du Colombier 	LapicSVR	= 0x00F0,	/* Spurious Interrupt Vector */
207dd7cddfSDavid du Colombier 	LapicISR	= 0x0100,	/* Interrupt Status (8 registers) */
217dd7cddfSDavid du Colombier 	LapicTMR	= 0x0180,	/* Trigger Mode (8 registers) */
227dd7cddfSDavid du Colombier 	LapicIRR	= 0x0200,	/* Interrupt Request (8 registers) */
237dd7cddfSDavid du Colombier 	LapicESR	= 0x0280,	/* Error Status */
247dd7cddfSDavid du Colombier 	LapicICRLO	= 0x0300,	/* Interrupt Command */
257dd7cddfSDavid du Colombier 	LapicICRHI	= 0x0310,	/* Interrupt Command [63:32] */
267dd7cddfSDavid du Colombier 	LapicTIMER	= 0x0320,	/* Local Vector Table 0 (TIMER) */
27aedc1c01SDavid du Colombier 	LapicPCINT	= 0x0340,	/* Performance Counter LVT */
287dd7cddfSDavid du Colombier 	LapicLINT0	= 0x0350,	/* Local Vector Table 1 (LINT0) */
297dd7cddfSDavid du Colombier 	LapicLINT1	= 0x0360,	/* Local Vector Table 2 (LINT1) */
307dd7cddfSDavid du Colombier 	LapicERROR	= 0x0370,	/* Local Vector Table 3 (ERROR) */
317dd7cddfSDavid du Colombier 	LapicTICR	= 0x0380,	/* Timer Initial Count */
327dd7cddfSDavid du Colombier 	LapicTCCR	= 0x0390,	/* Timer Current Count */
337dd7cddfSDavid du Colombier 	LapicTDCR	= 0x03E0,	/* Timer Divide Configuration */
347dd7cddfSDavid du Colombier };
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier enum {					/* LapicSVR */
377dd7cddfSDavid du Colombier 	LapicENABLE	= 0x00000100,	/* Unit Enable */
387dd7cddfSDavid du Colombier 	LapicFOCUS	= 0x00000200,	/* Focus Processor Checking Disable */
397dd7cddfSDavid du Colombier };
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier enum {					/* LapicICRLO */
427dd7cddfSDavid du Colombier 					/* [14] IPI Trigger Mode Level (RW) */
437dd7cddfSDavid du Colombier 	LapicDEASSERT	= 0x00000000,	/* Deassert level-sensitive interrupt */
447dd7cddfSDavid du Colombier 	LapicASSERT	= 0x00004000,	/* Assert level-sensitive interrupt */
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier 					/* [17:16] Remote Read Status */
477dd7cddfSDavid du Colombier 	LapicINVALID	= 0x00000000,	/* Invalid */
487dd7cddfSDavid du Colombier 	LapicWAIT	= 0x00010000,	/* In-Progress */
497dd7cddfSDavid du Colombier 	LapicVALID	= 0x00020000,	/* Valid */
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 					/* [19:18] Destination Shorthand */
527dd7cddfSDavid du Colombier 	LapicFIELD	= 0x00000000,	/* No shorthand */
537dd7cddfSDavid du Colombier 	LapicSELF	= 0x00040000,	/* Self is single destination */
547dd7cddfSDavid du Colombier 	LapicALLINC	= 0x00080000,	/* All including self */
557dd7cddfSDavid du Colombier 	LapicALLEXC	= 0x000C0000,	/* All Excluding self */
567dd7cddfSDavid du Colombier };
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier enum {					/* LapicESR */
597dd7cddfSDavid du Colombier 	LapicSENDCS	= 0x00000001,	/* Send CS Error */
607dd7cddfSDavid du Colombier 	LapicRCVCS	= 0x00000002,	/* Receive CS Error */
617dd7cddfSDavid du Colombier 	LapicSENDACCEPT	= 0x00000004,	/* Send Accept Error */
627dd7cddfSDavid du Colombier 	LapicRCVACCEPT	= 0x00000008,	/* Receive Accept Error */
637dd7cddfSDavid du Colombier 	LapicSENDVECTOR	= 0x00000020,	/* Send Illegal Vector */
647dd7cddfSDavid du Colombier 	LapicRCVVECTOR	= 0x00000040,	/* Receive Illegal Vector */
657dd7cddfSDavid du Colombier 	LapicREGISTER	= 0x00000080,	/* Illegal Register Address */
667dd7cddfSDavid du Colombier };
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier enum {					/* LapicTIMER */
697dd7cddfSDavid du Colombier 					/* [17] Timer Mode (RW) */
707dd7cddfSDavid du Colombier 	LapicONESHOT	= 0x00000000,	/* One-shot */
717dd7cddfSDavid du Colombier 	LapicPERIODIC	= 0x00020000,	/* Periodic */
727dd7cddfSDavid du Colombier 
737dd7cddfSDavid du Colombier 					/* [19:18] Timer Base (RW) */
747dd7cddfSDavid du Colombier 	LapicCLKIN	= 0x00000000,	/* use CLKIN as input */
757dd7cddfSDavid du Colombier 	LapicTMBASE	= 0x00040000,	/* use TMBASE */
767dd7cddfSDavid du Colombier 	LapicDIVIDER	= 0x00080000,	/* use output of the divider */
777dd7cddfSDavid du Colombier };
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier enum {					/* LapicTDCR */
807dd7cddfSDavid du Colombier 	LapicX2		= 0x00000000,	/* divide by 2 */
817dd7cddfSDavid du Colombier 	LapicX4		= 0x00000001,	/* divide by 4 */
827dd7cddfSDavid du Colombier 	LapicX8		= 0x00000002,	/* divide by 8 */
837dd7cddfSDavid du Colombier 	LapicX16	= 0x00000003,	/* divide by 16 */
847dd7cddfSDavid du Colombier 	LapicX32	= 0x00000008,	/* divide by 32 */
857dd7cddfSDavid du Colombier 	LapicX64	= 0x00000009,	/* divide by 64 */
867dd7cddfSDavid du Colombier 	LapicX128	= 0x0000000A,	/* divide by 128 */
877dd7cddfSDavid du Colombier 	LapicX1		= 0x0000000B,	/* divide by 1 */
887dd7cddfSDavid du Colombier };
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier static ulong* lapicbase;
919a747e4fSDavid du Colombier 
929a747e4fSDavid du Colombier struct
939a747e4fSDavid du Colombier {
949a747e4fSDavid du Colombier 	uvlong	hz;
959a747e4fSDavid du Colombier 	ulong	max;
969a747e4fSDavid du Colombier 	ulong	min;
973ff48bf5SDavid du Colombier 	ulong	div;
989a747e4fSDavid du Colombier } lapictimer;
997dd7cddfSDavid du Colombier 
1004fafed5dSDavid du Colombier static ulong
lapicr(int r)1017dd7cddfSDavid du Colombier lapicr(int r)
1027dd7cddfSDavid du Colombier {
10300a4193cSDavid du Colombier 	if(lapicbase == 0)
10400a4193cSDavid du Colombier 		panic("lapicr: no lapic");
1057dd7cddfSDavid du Colombier 	return *(lapicbase+(r/sizeof(*lapicbase)));
1067dd7cddfSDavid du Colombier }
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier static void
lapicw(int r,ulong data)1094fafed5dSDavid du Colombier lapicw(int r, ulong data)
1107dd7cddfSDavid du Colombier {
11100a4193cSDavid du Colombier 	if(lapicbase == 0)
11200a4193cSDavid du Colombier 		panic("lapicw: no lapic");
1137dd7cddfSDavid du Colombier 	*(lapicbase+(r/sizeof(*lapicbase))) = data;
1147dd7cddfSDavid du Colombier 	data = *(lapicbase+(LapicID/sizeof(*lapicbase)));
1157dd7cddfSDavid du Colombier 	USED(data);
1167dd7cddfSDavid du Colombier }
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier void
lapiconline(void)1197dd7cddfSDavid du Colombier lapiconline(void)
1207dd7cddfSDavid du Colombier {
1217dd7cddfSDavid du Colombier 	/*
1227dd7cddfSDavid du Colombier 	 * Reload the timer to de-synchronise the processors,
1237dd7cddfSDavid du Colombier 	 * then lower the task priority to allow interrupts to be
1247dd7cddfSDavid du Colombier 	 * accepted by the APIC.
1257dd7cddfSDavid du Colombier 	 */
1267dd7cddfSDavid du Colombier 	microdelay((TK2MS(1)*1000/conf.nmach) * m->machno);
1279a747e4fSDavid du Colombier 	lapicw(LapicTICR, lapictimer.max);
1287dd7cddfSDavid du Colombier 	lapicw(LapicTIMER, LapicCLKIN|LapicPERIODIC|(VectorPIC+IrqTIMER));
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	lapicw(LapicTPR, 0);
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier 
1339a747e4fSDavid du Colombier /*
1349a747e4fSDavid du Colombier  *  use the i8253 clock to figure out our lapic timer rate.
1359a747e4fSDavid du Colombier  */
1367dd7cddfSDavid du Colombier static void
lapictimerinit(void)1377dd7cddfSDavid du Colombier lapictimerinit(void)
1387dd7cddfSDavid du Colombier {
1399a747e4fSDavid du Colombier 	uvlong x, v, hz;
1407dd7cddfSDavid du Colombier 
1417dd7cddfSDavid du Colombier 	v = m->cpuhz/1000;
1427dd7cddfSDavid du Colombier 	lapicw(LapicTDCR, LapicX1);
1437dd7cddfSDavid du Colombier 	lapicw(LapicTIMER, ApicIMASK|LapicCLKIN|LapicONESHOT|(VectorPIC+IrqTIMER));
1447dd7cddfSDavid du Colombier 
1459a747e4fSDavid du Colombier 	if(lapictimer.hz == 0ULL){
1469a747e4fSDavid du Colombier 		x = fastticks(&hz);
1479a747e4fSDavid du Colombier 		x += hz/10;
1489a747e4fSDavid du Colombier 		lapicw(LapicTICR, 0xffffffff);
1497dd7cddfSDavid du Colombier 		do{
1509a747e4fSDavid du Colombier 			v = fastticks(nil);
1519a747e4fSDavid du Colombier 		}while(v < x);
1527dd7cddfSDavid du Colombier 
1539a747e4fSDavid du Colombier 		lapictimer.hz = (0xffffffffUL-lapicr(LapicTCCR))*10;
1549a747e4fSDavid du Colombier 		lapictimer.max = lapictimer.hz/HZ;
1559a747e4fSDavid du Colombier 		lapictimer.min = lapictimer.hz/(100*HZ);
1563ff48bf5SDavid du Colombier 
1577698de14SDavid du Colombier 		if(lapictimer.hz > hz-(hz/10)){
1587698de14SDavid du Colombier 			if(lapictimer.hz > hz+(hz/10))
1597698de14SDavid du Colombier 				panic("lapic clock %lld > cpu clock > %lld\n",
1604fafed5dSDavid du Colombier 					lapictimer.hz, hz);
1617698de14SDavid du Colombier 			lapictimer.hz = hz;
1627698de14SDavid du Colombier 		}
163abfa367dSDavid du Colombier 		assert(lapictimer.hz != 0);
1643ff48bf5SDavid du Colombier 		lapictimer.div = hz/lapictimer.hz;
1657dd7cddfSDavid du Colombier 	}
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier void
lapicinit(Apic * apic)1697dd7cddfSDavid du Colombier lapicinit(Apic* apic)
1707dd7cddfSDavid du Colombier {
171bd2f1373SDavid du Colombier 	ulong dfr, ldr, lvt;
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	if(lapicbase == 0)
1747dd7cddfSDavid du Colombier 		lapicbase = apic->addr;
17500a4193cSDavid du Colombier 	if(lapicbase == 0) {
17600a4193cSDavid du Colombier 		print("lapicinit: no lapic\n");
17700a4193cSDavid du Colombier 		return;
17800a4193cSDavid du Colombier 	}
1797dd7cddfSDavid du Colombier 
180bd2f1373SDavid du Colombier 	/*
181bd2f1373SDavid du Colombier 	 * These don't really matter in Physical mode;
182bd2f1373SDavid du Colombier 	 * set the defaults anyway.
183bd2f1373SDavid du Colombier 	 */
184bd2f1373SDavid du Colombier 	if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0)
185bd2f1373SDavid du Colombier 		dfr = 0xf0000000;
186bd2f1373SDavid du Colombier 	else
187bd2f1373SDavid du Colombier 		dfr = 0xffffffff;
188bd2f1373SDavid du Colombier 	ldr = 0x00000000;
189bd2f1373SDavid du Colombier 
190bd2f1373SDavid du Colombier 	lapicw(LapicDFR, dfr);
191bd2f1373SDavid du Colombier 	lapicw(LapicLDR, ldr);
192bd2f1373SDavid du Colombier 	lapicw(LapicTPR, 0xff);
1937dd7cddfSDavid du Colombier 	lapicw(LapicSVR, LapicENABLE|(VectorPIC+IrqSPURIOUS));
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier 	lapictimerinit();
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	/*
1987dd7cddfSDavid du Colombier 	 * Some Pentium revisions have a bug whereby spurious
1997dd7cddfSDavid du Colombier 	 * interrupts are generated in the through-local mode.
2007dd7cddfSDavid du Colombier 	 */
2017dd7cddfSDavid du Colombier 	switch(m->cpuidax & 0xFFF){
2027dd7cddfSDavid du Colombier 	case 0x526:				/* stepping cB1 */
2037dd7cddfSDavid du Colombier 	case 0x52B:				/* stepping E0 */
2047dd7cddfSDavid du Colombier 	case 0x52C:				/* stepping cC0 */
2057dd7cddfSDavid du Colombier 		wrmsr(0x0E, 1<<14);		/* TR12 */
2067dd7cddfSDavid du Colombier 		break;
2077dd7cddfSDavid du Colombier 	}
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier 	/*
2107dd7cddfSDavid du Colombier 	 * Set the local interrupts. It's likely these should just be
2117dd7cddfSDavid du Colombier 	 * masked off for SMP mode as some Pentium Pros have problems if
2127dd7cddfSDavid du Colombier 	 * LINT[01] are set to ExtINT.
2137dd7cddfSDavid du Colombier 	 * Acknowledge any outstanding interrupts.
2147dd7cddfSDavid du Colombier 	lapicw(LapicLINT0, apic->lintr[0]);
2157dd7cddfSDavid du Colombier 	lapicw(LapicLINT1, apic->lintr[1]);
2167dd7cddfSDavid du Colombier 	 */
2177dd7cddfSDavid du Colombier 	lapiceoi(0);
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier 	lvt = (lapicr(LapicVER)>>16) & 0xFF;
2207dd7cddfSDavid du Colombier 	if(lvt >= 4)
221*afaac077SDavid du Colombier 		lapicw(LapicPCINT, ApicIMASK|(VectorPIC+IrqPCINT));
2227dd7cddfSDavid du Colombier 	lapicw(LapicERROR, VectorPIC+IrqERROR);
2237dd7cddfSDavid du Colombier 	lapicw(LapicESR, 0);
2247dd7cddfSDavid du Colombier 	lapicr(LapicESR);
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier 	/*
2277dd7cddfSDavid du Colombier 	 * Issue an INIT Level De-Assert to synchronise arbitration ID's.
2287dd7cddfSDavid du Colombier 	 */
2297dd7cddfSDavid du Colombier 	lapicw(LapicICRHI, 0);
2307dd7cddfSDavid du Colombier 	lapicw(LapicICRLO, LapicALLINC|ApicLEVEL|LapicDEASSERT|ApicINIT);
2317dd7cddfSDavid du Colombier 	while(lapicr(LapicICRLO) & ApicDELIVS)
2327dd7cddfSDavid du Colombier 		;
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier 	/*
2357dd7cddfSDavid du Colombier 	 * Do not allow acceptance of interrupts until all initialisation
2367dd7cddfSDavid du Colombier 	 * for this processor is done. For the bootstrap processor this can be
237a650be7dSDavid du Colombier 	 * early during initialisation. For the application processors this should
2387dd7cddfSDavid du Colombier 	 * be after the bootstrap processor has lowered priority and is accepting
2397dd7cddfSDavid du Colombier 	 * interrupts.
2407dd7cddfSDavid du Colombier 	lapicw(LapicTPR, 0);
2417dd7cddfSDavid du Colombier 	 */
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier void
lapicstartap(Apic * apic,int v)2457dd7cddfSDavid du Colombier lapicstartap(Apic* apic, int v)
2467dd7cddfSDavid du Colombier {
2474fafed5dSDavid du Colombier 	int i;
2484fafed5dSDavid du Colombier 	ulong crhi;
2497dd7cddfSDavid du Colombier 
250f09ab852SDavid du Colombier 	/* make apic's processor do a warm reset */
2517dd7cddfSDavid du Colombier 	crhi = apic->apicno<<24;
2527dd7cddfSDavid du Colombier 	lapicw(LapicICRHI, crhi);
2537dd7cddfSDavid du Colombier 	lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicASSERT|ApicINIT);
2547dd7cddfSDavid du Colombier 	microdelay(200);
2557dd7cddfSDavid du Colombier 	lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicDEASSERT|ApicINIT);
2567dd7cddfSDavid du Colombier 	delay(10);
2577dd7cddfSDavid du Colombier 
258f09ab852SDavid du Colombier 	/* assumes apic is not an 82489dx */
2597dd7cddfSDavid du Colombier 	for(i = 0; i < 2; i++){
2607dd7cddfSDavid du Colombier 		lapicw(LapicICRHI, crhi);
261f09ab852SDavid du Colombier 		/* make apic's processor start at v in real mode */
2627dd7cddfSDavid du Colombier 		lapicw(LapicICRLO, LapicFIELD|ApicEDGE|ApicSTARTUP|(v/BY2PG));
2637dd7cddfSDavid du Colombier 		microdelay(200);
2647dd7cddfSDavid du Colombier 	}
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier void
lapicerror(Ureg *,void *)2687dd7cddfSDavid du Colombier lapicerror(Ureg*, void*)
2697dd7cddfSDavid du Colombier {
2704fafed5dSDavid du Colombier 	ulong esr;
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 	lapicw(LapicESR, 0);
2737dd7cddfSDavid du Colombier 	esr = lapicr(LapicESR);
2747dd7cddfSDavid du Colombier 	switch(m->cpuidax & 0xFFF){
2757dd7cddfSDavid du Colombier 	case 0x526:				/* stepping cB1 */
2767dd7cddfSDavid du Colombier 	case 0x52B:				/* stepping E0 */
2777dd7cddfSDavid du Colombier 	case 0x52C:				/* stepping cC0 */
2787dd7cddfSDavid du Colombier 		return;
2797dd7cddfSDavid du Colombier 	}
2804fafed5dSDavid du Colombier 	print("cpu%d: lapicerror: 0x%8.8luX\n", m->machno, esr);
2817dd7cddfSDavid du Colombier }
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier void
lapicspurious(Ureg *,void *)2847dd7cddfSDavid du Colombier lapicspurious(Ureg*, void*)
2857dd7cddfSDavid du Colombier {
2867dd7cddfSDavid du Colombier 	print("cpu%d: lapicspurious\n", m->machno);
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier int
lapicisr(int v)2907dd7cddfSDavid du Colombier lapicisr(int v)
2917dd7cddfSDavid du Colombier {
2924fafed5dSDavid du Colombier 	ulong isr;
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier 	isr = lapicr(LapicISR + (v/32));
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier 	return isr & (1<<(v%32));
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier int
lapiceoi(int v)3007dd7cddfSDavid du Colombier lapiceoi(int v)
3017dd7cddfSDavid du Colombier {
3027dd7cddfSDavid du Colombier 	lapicw(LapicEOI, 0);
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 	return v;
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier void
lapicicrw(ulong hi,ulong lo)3084fafed5dSDavid du Colombier lapicicrw(ulong hi, ulong lo)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier 	lapicw(LapicICRHI, hi);
3117dd7cddfSDavid du Colombier 	lapicw(LapicICRLO, lo);
3127dd7cddfSDavid du Colombier }
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier void
ioapicrdtr(Apic * apic,int sel,int * hi,int * lo)3157dd7cddfSDavid du Colombier ioapicrdtr(Apic* apic, int sel, int* hi, int* lo)
3167dd7cddfSDavid du Colombier {
3177dd7cddfSDavid du Colombier 	ulong *iowin;
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 	iowin = apic->addr+(0x10/sizeof(ulong));
3207dd7cddfSDavid du Colombier 	sel = IoapicRDT + 2*sel;
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier 	lock(apic);
3237dd7cddfSDavid du Colombier 	*apic->addr = sel+1;
3247dd7cddfSDavid du Colombier 	if(hi)
3257dd7cddfSDavid du Colombier 		*hi = *iowin;
3267dd7cddfSDavid du Colombier 	*apic->addr = sel;
3277dd7cddfSDavid du Colombier 	if(lo)
3287dd7cddfSDavid du Colombier 		*lo = *iowin;
3297dd7cddfSDavid du Colombier 	unlock(apic);
3307dd7cddfSDavid du Colombier }
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier void
ioapicrdtw(Apic * apic,int sel,int hi,int lo)3337dd7cddfSDavid du Colombier ioapicrdtw(Apic* apic, int sel, int hi, int lo)
3347dd7cddfSDavid du Colombier {
3357dd7cddfSDavid du Colombier 	ulong *iowin;
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier 	iowin = apic->addr+(0x10/sizeof(ulong));
3387dd7cddfSDavid du Colombier 	sel = IoapicRDT + 2*sel;
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 	lock(apic);
3417dd7cddfSDavid du Colombier 	*apic->addr = sel+1;
3427dd7cddfSDavid du Colombier 	*iowin = hi;
3437dd7cddfSDavid du Colombier 	*apic->addr = sel;
3447dd7cddfSDavid du Colombier 	*iowin = lo;
3457dd7cddfSDavid du Colombier 	unlock(apic);
3467dd7cddfSDavid du Colombier }
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier void
ioapicinit(Apic * apic,int apicno)3497dd7cddfSDavid du Colombier ioapicinit(Apic* apic, int apicno)
3507dd7cddfSDavid du Colombier {
3517dd7cddfSDavid du Colombier 	int hi, lo, v;
3527dd7cddfSDavid du Colombier 	ulong *iowin;
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier 	/*
3557dd7cddfSDavid du Colombier 	 * Initialise the I/O APIC.
3567dd7cddfSDavid du Colombier 	 * The MultiProcessor Specification says it is the responsibility
3577dd7cddfSDavid du Colombier 	 * of the O/S to set the APIC id.
3587dd7cddfSDavid du Colombier 	 * Make sure interrupts are all masked off for now.
3597dd7cddfSDavid du Colombier 	 */
3607dd7cddfSDavid du Colombier 	iowin = apic->addr+(0x10/sizeof(ulong));
3617dd7cddfSDavid du Colombier 	lock(apic);
3627dd7cddfSDavid du Colombier 	*apic->addr = IoapicVER;
3637dd7cddfSDavid du Colombier 	apic->mre = (*iowin>>16) & 0xFF;
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier 	*apic->addr = IoapicID;
3667dd7cddfSDavid du Colombier 	*iowin = apicno<<24;
3677dd7cddfSDavid du Colombier 	unlock(apic);
3687dd7cddfSDavid du Colombier 
3697dd7cddfSDavid du Colombier 	hi = 0;
3707dd7cddfSDavid du Colombier 	lo = ApicIMASK;
3717dd7cddfSDavid du Colombier 	for(v = 0; v <= apic->mre; v++)
3727dd7cddfSDavid du Colombier 		ioapicrdtw(apic, v, hi, lo);
3737dd7cddfSDavid du Colombier }
3749a747e4fSDavid du Colombier 
3759a747e4fSDavid du Colombier void
lapictimerset(uvlong next)3769a747e4fSDavid du Colombier lapictimerset(uvlong next)
3779a747e4fSDavid du Colombier {
378da51d93aSDavid du Colombier 	vlong period;
3799a747e4fSDavid du Colombier 	int x;
3809a747e4fSDavid du Colombier 
3819a747e4fSDavid du Colombier 	x = splhi();
3829a747e4fSDavid du Colombier 	lock(&m->apictimerlock);
3833ff48bf5SDavid du Colombier 
3849a747e4fSDavid du Colombier 	period = lapictimer.max;
3859a747e4fSDavid du Colombier 	if(next != 0){
3869a747e4fSDavid du Colombier 		period = next - fastticks(nil);
387abfa367dSDavid du Colombier 		if (lapictimer.div == 0)
388abfa367dSDavid du Colombier 			panic("lapictimerset: zero lapictimer.div");
3893ff48bf5SDavid du Colombier 		period /= lapictimer.div;
3909a747e4fSDavid du Colombier 
3919a747e4fSDavid du Colombier 		if(period < lapictimer.min)
3929a747e4fSDavid du Colombier 			period = lapictimer.min;
3939a747e4fSDavid du Colombier 		else if(period > lapictimer.max - lapictimer.min)
3949a747e4fSDavid du Colombier 			period = lapictimer.max;
3959a747e4fSDavid du Colombier 	}
3969a747e4fSDavid du Colombier 	lapicw(LapicTICR, period);
3979a747e4fSDavid du Colombier 
3989a747e4fSDavid du Colombier 	unlock(&m->apictimerlock);
3999a747e4fSDavid du Colombier 	splx(x);
4009a747e4fSDavid du Colombier }
4019a747e4fSDavid du Colombier 
4029a747e4fSDavid du Colombier void
lapicclock(Ureg * u,void *)4039a747e4fSDavid du Colombier lapicclock(Ureg *u, void*)
4049a747e4fSDavid du Colombier {
40526d1d1dfSDavid du Colombier 	/*
40626d1d1dfSDavid du Colombier 	 * since the MTRR updates need to be synchronized across processors,
40726d1d1dfSDavid du Colombier 	 * we want to do this within the clock tick.
40826d1d1dfSDavid du Colombier 	 */
40926d1d1dfSDavid du Colombier 	mtrrclock();
4109a747e4fSDavid du Colombier 	timerintr(u, 0);
4119a747e4fSDavid du Colombier }
4124de34a7eSDavid du Colombier 
4134de34a7eSDavid du Colombier void
lapicintron(void)4144de34a7eSDavid du Colombier lapicintron(void)
4154de34a7eSDavid du Colombier {
4164de34a7eSDavid du Colombier 	lapicw(LapicTPR, 0);
4174de34a7eSDavid du Colombier }
4184de34a7eSDavid du Colombier 
4194de34a7eSDavid du Colombier void
lapicintroff(void)4204de34a7eSDavid du Colombier lapicintroff(void)
4214de34a7eSDavid du Colombier {
4224de34a7eSDavid du Colombier 	lapicw(LapicTPR, 0xFF);
4234de34a7eSDavid du Colombier }
4244de34a7eSDavid du Colombier 
425aedc1c01SDavid du Colombier void
lapicnmienable(void)426aedc1c01SDavid du Colombier lapicnmienable(void)
427aedc1c01SDavid du Colombier {
428*afaac077SDavid du Colombier 	/*
429*afaac077SDavid du Colombier 	 * On the one hand the manual says the vector information
430*afaac077SDavid du Colombier 	 * is ignored if the delivery mode is NMI, and on the other
431*afaac077SDavid du Colombier 	 * a "Receive Illegal Vector" should be generated for a
432*afaac077SDavid du Colombier 	 * vector in the range 0 through 15.
433*afaac077SDavid du Colombier 	 * Some implementations generate the error interrupt if the
434*afaac077SDavid du Colombier 	 * NMI vector is invalid, so always give a valid value.
435*afaac077SDavid du Colombier 	 */
43600a4193cSDavid du Colombier 	if (lapicbase)
437*afaac077SDavid du Colombier 		lapicw(LapicPCINT, ApicNMI|(VectorPIC+IrqPCINT));
43800a4193cSDavid du Colombier 	else
43900a4193cSDavid du Colombier 		print("lapicnmienable: no lapic\n");
440aedc1c01SDavid du Colombier }
441aedc1c01SDavid du Colombier 
442aedc1c01SDavid du Colombier void
lapicnmidisable(void)443aedc1c01SDavid du Colombier lapicnmidisable(void)
444aedc1c01SDavid du Colombier {
44500a4193cSDavid du Colombier 	if (lapicbase)
446*afaac077SDavid du Colombier 		lapicw(LapicPCINT, ApicIMASK|(VectorPIC+IrqPCINT));
44700a4193cSDavid du Colombier 	else
44800a4193cSDavid du Colombier 		print("lapicnmidisable: no lapic\n");
449aedc1c01SDavid du Colombier }
450