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