]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/archmp.c
disable tscticks in pc kernel (for now)
[plan9front.git] / sys / src / 9 / pc / archmp.c
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 static PCMP *pcmp;
11
12 static char* buses[] = {
13         "CBUSI ",
14         "CBUSII",
15         "EISA  ",
16         "FUTURE",
17         "INTERN",
18         "ISA   ",
19         "MBI   ",
20         "MBII  ",
21         "MCA   ",
22         "MPI   ",
23         "MPSA  ",
24         "NUBUS ",
25         "PCI   ",
26         "PCMCIA",
27         "TC    ",
28         "VL    ",
29         "VME   ",
30         "XPRESS",
31         0,
32 };
33
34 static Bus*
35 mpgetbus(int busno)
36 {
37         Bus *bus;
38
39         for(bus = mpbus; bus; bus = bus->next)
40                 if(bus->busno == busno)
41                         return bus;
42
43         print("mpgetbus: can't find bus %d\n", busno);
44
45         return 0;
46 }
47
48 static Apic*
49 mkprocessor(PCMPprocessor* p)
50 {
51         static int machno = 1;
52         int apicno;
53         Apic *apic;
54
55         apicno = p->apicno;
56         if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpapic[apicno] != nil)
57                 return 0;
58
59         if((apic = xalloc(sizeof(Apic))) == nil)
60                 panic("mkprocessor: no memory for Apic");
61         apic->type = PcmpPROCESSOR;
62         apic->apicno = apicno;
63         apic->flags = p->flags;
64         apic->lintr[0] = ApicIMASK;
65         apic->lintr[1] = ApicIMASK;
66         if(p->flags & PcmpBP)
67                 apic->machno = 0;
68         else
69                 apic->machno = machno++;
70         mpapic[apicno] = apic;
71
72         return apic;
73 }
74
75 static Bus*
76 mkbus(PCMPbus* p)
77 {
78         Bus *bus;
79         int i;
80
81         for(i = 0; buses[i]; i++)
82                 if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
83                         break;
84         if(buses[i] == 0)
85                 return 0;
86
87         if((bus = xalloc(sizeof(Bus))) == nil)
88                 panic("mkbus: no memory for Bus");
89         if(mpbus)
90                 mpbuslast->next = bus;
91         else
92                 mpbus = bus;
93         mpbuslast = bus;
94
95         bus->type = i;
96         bus->busno = p->busno;
97         if(bus->type == BusEISA){
98                 bus->po = PcmpLOW;
99                 bus->el = PcmpLEVEL;
100                 if(mpeisabus != -1)
101                         print("mkbus: more than one EISA bus\n");
102                 mpeisabus = bus->busno;
103         }
104         else if(bus->type == BusPCI){
105                 bus->po = PcmpLOW;
106                 bus->el = PcmpLEVEL;
107         }
108         else if(bus->type == BusISA){
109                 bus->po = PcmpHIGH;
110                 bus->el = PcmpEDGE;
111                 if(mpisabus != -1)
112                         print("mkbus: more than one ISA bus\n");
113                 mpisabus = bus->busno;
114         }
115         else{
116                 bus->po = PcmpHIGH;
117                 bus->el = PcmpEDGE;
118         }
119
120         return bus;
121 }
122
123 static Apic*
124 mkioapic(PCMPioapic* p)
125 {
126         void *va;
127         int apicno;
128         Apic *apic;
129
130         apicno = p->apicno;
131         if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpioapic[apicno] != nil)
132                 return 0;
133         /*
134          * Map the I/O APIC.
135          */
136         if((va = vmap(p->addr, 1024)) == nil)
137                 return 0;
138         if((apic = xalloc(sizeof(Apic))) == nil)
139                 panic("mkioapic: no memory for Apic");
140         apic->type = PcmpIOAPIC;
141         apic->apicno = apicno;
142         apic->addr = va;
143         apic->paddr = p->addr;
144         apic->flags = p->flags;
145         mpioapic[apicno] = apic;
146
147         return apic;
148 }
149
150 static Aintr*
151 mkiointr(PCMPintr* p)
152 {
153         Bus *bus;
154         Aintr *aintr;
155         PCMPintr* pcmpintr;
156
157         /*
158          * According to the MultiProcessor Specification, a destination
159          * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
160          * It's unclear how that can possibly be correct so treat it as
161          * an error for now.
162          */
163         if(p->apicno > MaxAPICNO || mpioapic[p->apicno] == nil)
164                 return 0;
165         
166         if((bus = mpgetbus(p->busno)) == 0)
167                 return 0;
168
169         if((aintr = xalloc(sizeof(Aintr))) == nil)
170                 panic("mkiointr: no memory for Aintr");
171         aintr->intr = p;
172
173         if(0)
174                 print("mkiointr: type %d intr type %d flags %#o "
175                         "bus %d irq %d apicno %d intin %d\n",
176                         p->type, p->intr, p->flags,
177                         p->busno, p->irq, p->apicno, p->intin);
178         /*
179          * Hack for Intel SR1520ML motherboard, which BIOS describes
180          * the i82575 dual ethernet controllers incorrectly.
181          */
182         if(memcmp(pcmp->product, "INTEL   X38MLST     ", 20) == 0){
183                 if(p->busno == 1 && p->intin == 16 && p->irq == 1){
184                         if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
185                                 panic("iointr: no memory for PCMPintr");
186                         memmove(pcmpintr, p, sizeof(PCMPintr));
187                         print("mkiointr: %20.20s bus %d intin %d irq %d\n",
188                                 (char*)pcmp->product,
189                                 pcmpintr->busno, pcmpintr->intin,
190                                 pcmpintr->irq);
191                         pcmpintr->intin = 17;
192                         aintr->intr = pcmpintr;
193                 }
194         }
195         aintr->apic = mpioapic[p->apicno];
196         aintr->next = bus->aintr;
197         bus->aintr = aintr;
198
199         return aintr;
200 }
201
202 static int
203 mklintr(PCMPintr* p)
204 {
205         Apic *apic;
206         Bus *bus;
207         int i, intin, v;
208
209         /*
210          * The offsets of vectors for LINT[01] are known to be
211          * 0 and 1 from the local APIC vector space at VectorLAPIC.
212          */
213         if((bus = mpgetbus(p->busno)) == 0)
214                 return 0;
215         intin = p->intin;
216
217         /*
218          * Pentium Pros have problems if LINT[01] are set to ExtINT
219          * so just bag it, SMP mode shouldn't need ExtINT anyway.
220          */
221         if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
222                 v = ApicIMASK;
223         else
224                 v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
225
226         if(p->apicno == 0xFF){
227                 for(i=0; i<=MaxAPICNO; i++){
228                         if((apic = mpapic[i]) == nil)
229                                 continue;
230                         if(apic->flags & PcmpEN)
231                                 apic->lintr[intin] = v;
232                 }
233         }
234         else{
235                 if(apic = mpapic[p->apicno])
236                         if(apic->flags & PcmpEN)
237                                 apic->lintr[intin] = v;
238         }
239
240         return v;
241 }
242
243 static void
244 dumpmp(uchar *p, uchar *e)
245 {
246         int i;
247
248         for(i = 0; p < e; p++) {
249                 if((i % 16) == 0) print("*mp%d=", i/16);
250                 print("%.2x ", *p);
251                 if((++i % 16) == 0) print("\n");
252         }
253         if((i % 16) != 0) print("\n");
254 }
255
256
257 static void
258 mpoverride(uchar** newp, uchar** e)
259 {
260         int size, i, j;
261         char buf[20];
262         uchar* p;
263         char* s;
264         
265         size = atoi(getconf("*mp"));
266         if(size == 0) panic("mpoverride: invalid size in *mp");
267         *newp = p = xalloc(size);
268         if(p == nil) panic("mpoverride: can't allocate memory");
269         *e = p + size;
270         for(i = 0; ; i++){
271                 snprint(buf, sizeof buf, "*mp%d", i);
272                 s = getconf(buf);
273                 if(s == nil) break;
274                 while(*s){
275                         j = strtol(s, &s, 16);
276                         if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
277                         if(p >= *e) panic("mpoverride: overflow in %s", buf);
278                         *p++ = j;
279                 }
280         }
281         if(p != *e) panic("mpoverride: size doesn't match");
282 }
283
284 static void
285 pcmpinit(void)
286 {
287         uchar *p, *e;
288         Apic *apic;
289         void *va;
290
291         /*
292          * Map the local APIC.
293          */
294         va = vmap(pcmp->lapicbase, 1024);
295         print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
296         if(va == nil)
297                 panic("pcmpinit: cannot map lapic %.8lux", pcmp->lapicbase);
298
299         p = ((uchar*)pcmp)+sizeof(PCMP);
300         e = ((uchar*)pcmp)+pcmp->length;
301         if(getconf("*dumpmp") != nil)
302                 dumpmp(p, e);
303         if(getconf("*mp") != nil)
304                 mpoverride(&p, &e);
305
306         /*
307          * Run through the table saving information needed for starting
308          * application processors and initialising any I/O APICs. The table
309          * is guaranteed to be in order such that only one pass is necessary.
310          */
311         while(p < e) switch(*p){
312         default:
313                 print("pcmpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
314                         *p, e-p);
315                 while(p < e){
316                         print("%uX ", *p);
317                         p++;
318                 }
319                 break;
320
321         case PcmpPROCESSOR:
322                 if(apic = mkprocessor((PCMPprocessor*)p)){
323                         apic->addr = va;
324                         apic->paddr = pcmp->lapicbase;
325                 }
326                 p += sizeof(PCMPprocessor);
327                 continue;
328
329         case PcmpBUS:
330                 mkbus((PCMPbus*)p);
331                 p += sizeof(PCMPbus);
332                 continue;
333
334         case PcmpIOAPIC:
335                 if(apic = mkioapic((PCMPioapic*)p))
336                         ioapicinit(apic, apic->apicno);
337                 p += sizeof(PCMPioapic);
338                 continue;
339
340         case PcmpIOINTR:
341                 mkiointr((PCMPintr*)p);
342                 p += sizeof(PCMPintr);
343                 continue;
344
345         case PcmpLINTR:
346                 mklintr((PCMPintr*)p);
347                 p += sizeof(PCMPintr);
348                 continue;
349         }
350
351         /*
352          * Ininitalize local APIC and start application processors.
353          */
354         mpinit();
355 }
356
357 static int identify(void);
358
359 PCArch archmp = {
360 .id=            "_MP_", 
361 .ident=         identify,
362 .reset=         mpshutdown,
363 .intrinit=      pcmpinit,
364 .intrenable=    mpintrenable,
365 .intron=        lapicintron,
366 .introff=       lapicintroff,
367 .fastclock=     i8253read,
368 .timerset=      lapictimerset,
369 };
370
371 static int
372 identify(void)
373 {
374         char *cp;
375         _MP_ *_mp_;
376
377         if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
378                 return 1;
379
380         /*
381          * Search for an MP configuration table. For now,
382          * don't accept the default configurations (physaddr == 0).
383          * Check for correct signature, calculate the checksum and,
384          * if correct, check the version.
385          * To do: check extended table checksum.
386          */
387         if((_mp_ = sigsearch("_MP_")) == 0 || checksum(_mp_, sizeof(_MP_)) || 
388            (_mp_->physaddr == 0))
389                 return 1;
390
391         pcmp = KADDR(_mp_->physaddr);
392         if(memcmp(pcmp, "PCMP", 4) || checksum(pcmp, pcmp->length) ||
393            (pcmp->version != 1 && pcmp->version != 4)) {
394                 pcmp = nil;
395                 return 1;
396         }
397
398         return 0;
399 }