]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/alphapc/devarch.c
etheriwl: implement 4965 firmware bootstrap (untested)
[plan9front.git] / sys / src / 9 / alphapc / devarch.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 #include "../port/error.h"
8 #include        "axp.h"
9
10 typedef struct IOMap IOMap;
11 struct IOMap
12 {
13         IOMap   *next;
14         char    tag[13];
15         ulong   start;
16         ulong   end;
17 };
18
19 static struct
20 {
21         Lock;
22         IOMap   *m;
23         IOMap   *free;
24         IOMap   maps[32];               // some initial free maps
25
26         QLock   ql;                     // lock for reading map
27 } iomap;
28
29 enum {
30         Qdir = 0,
31         Qioalloc = 1,
32         Qiob,
33         Qiow,
34         Qiol,
35         Qbase,
36
37         Qmax = 16,
38 };
39
40 typedef long Rdwrfn(Chan*, void*, long, vlong);
41
42 static Rdwrfn *readfn[Qmax];
43 static Rdwrfn *writefn[Qmax];
44
45 static Dirtab archdir[] = {
46         ".",    { Qdir, 0, QTDIR },     0,      0555,
47         "ioalloc",      { Qioalloc, 0 },        0,      0444,
48         "iob",          { Qiob, 0 },            0,      0660,
49         "iow",          { Qiow, 0 },            0,      0660,
50         "iol",          { Qiol, 0 },            0,      0660,
51 };
52 Lock archwlock; /* the lock is only for changing archdir */
53 int narchdir = Qbase;
54 int (*_pcmspecial)(char *, ISAConf *);
55 void (*_pcmspecialclose)(int);
56
57 /*
58  * Add a file to the #P listing.  Once added, you can't delete it.
59  * You can't add a file with the same name as one already there,
60  * and you get a pointer to the Dirtab entry so you can do things
61  * like change the Qid version.  Changing the Qid path is disallowed.
62  */
63 Dirtab*
64 addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
65 {
66         int i;
67         Dirtab d;
68         Dirtab *dp;
69
70         memset(&d, 0, sizeof d);
71         strcpy(d.name, name);
72         d.perm = perm;
73
74         lock(&archwlock);
75         if(narchdir >= Qmax){
76                 unlock(&archwlock);
77                 return nil;
78         }
79
80         for(i=0; i<narchdir; i++)
81                 if(strcmp(archdir[i].name, name) == 0){
82                         unlock(&archwlock);
83                         return nil;
84                 }
85
86         d.qid.path = narchdir;
87         archdir[narchdir] = d;
88         readfn[narchdir] = rdfn;
89         writefn[narchdir] = wrfn;
90         dp = &archdir[narchdir++];
91         unlock(&archwlock);
92
93         return dp;
94 }
95
96 void
97 ioinit(void)
98 {
99         int i;
100
101         for(i = 0; i < nelem(iomap.maps)-1; i++)
102                 iomap.maps[i].next = &iomap.maps[i+1];
103         iomap.maps[i].next = nil;
104         iomap.free = iomap.maps;
105
106         // a dummy entry at 2^17
107         ioalloc(0x20000, 1, 0, "dummy");
108 }
109
110 //
111 //      alloc some io port space and remember who it was
112 //      alloced to.  if port < 0, find a free region.
113 //
114 int
115 ioalloc(int port, int size, int align, char *tag)
116 {
117         IOMap *m, **l;
118         int i;
119
120         lock(&iomap);
121         if(port < 0){
122                 // find a free port above 0x400 and below 0x1000
123                 port = 0x400;
124                 for(l = &iomap.m; *l; l = &(*l)->next){
125                         m = *l;
126                         i = m->start - port;
127                         if(i > size)
128                                 break;
129                         if(align > 0)
130                                 port = ((port+align-1)/align)*align;
131                         else
132                                 port = m->end;
133                 }
134                 if(*l == nil){
135                         unlock(&iomap);
136                         return -1;
137                 }
138         } else {
139                 // see if the space clashes with previously allocated ports
140                 for(l = &iomap.m; *l; l = &(*l)->next){
141                         m = *l;
142                         if(m->end <= port)
143                                 continue;
144                         if(m->start >= port+size)
145                                 break;
146                         unlock(&iomap);
147                         return -1;
148                 }
149         }
150         m = iomap.free;
151         if(m == nil){
152                 print("ioalloc: out of maps");
153                 unlock(&iomap);
154                 return port;
155         }
156         iomap.free = m->next;
157         m->next = *l;
158         m->start = port;
159         m->end = port + size;
160         strncpy(m->tag, tag, sizeof(m->tag));
161         m->tag[sizeof(m->tag)-1] = 0;
162         *l = m;
163
164         archdir[0].qid.vers++;
165
166         unlock(&iomap);
167         return m->start;
168 }
169
170 void
171 iofree(int port)
172 {
173         IOMap *m, **l;
174
175         lock(&iomap);
176         for(l = &iomap.m; *l; l = &(*l)->next){
177                 if((*l)->start == port){
178                         m = *l;
179                         *l = m->next;
180                         m->next = iomap.free;
181                         iomap.free = m;
182                         break;
183                 }
184                 if((*l)->start > port)
185                         break;
186         }
187         archdir[0].qid.vers++;
188         unlock(&iomap);
189 }
190
191 int
192 iounused(int start, int end)
193 {
194         IOMap *m;
195
196         for(m = iomap.m; m; m = m->next){
197                 if(start >= m->start && start < m->end
198                 || start <= m->start && end > m->start)
199                         return 0; 
200         }
201         return 1;
202 }
203
204 static void
205 checkport(int start, int end)
206 {
207         /* standard vga regs are OK */
208         if(start >= 0x2b0 && end <= 0x2df+1)
209                 return;
210         if(start >= 0x3c0 && end <= 0x3da+1)
211                 return;
212
213         if(iounused(start, end))
214                 return;
215         error(Eperm);
216 }
217
218 static Chan*
219 archattach(char* spec)
220 {
221         return devattach('P', spec);
222 }
223
224 Walkqid*
225 archwalk(Chan* c, Chan *nc, char** name, int nname)
226 {
227         return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
228 }
229
230 static int
231 archstat(Chan* c, uchar* dp, int n)
232 {
233         return devstat(c, dp, n, archdir, narchdir, devgen);
234 }
235
236 static Chan*
237 archopen(Chan* c, int omode)
238 {
239         return devopen(c, omode, archdir, nelem(archdir), devgen);
240 }
241
242 static void
243 archclose(Chan*)
244 {
245 }
246
247 enum
248 {
249         Linelen= 31,
250 };
251
252 static long
253 archread(Chan *c, void *a, long n, vlong offset)
254 {
255         char buf[Linelen+1], *p;
256         int port;
257         ushort *sp;
258         ulong *lp;
259         IOMap *m;
260         Rdwrfn *fn;
261
262         switch((ulong)c->qid.path){
263
264         case Qdir:
265                 return devdirread(c, a, n, archdir, nelem(archdir), devgen);
266
267         case Qiob:
268                 port = offset;
269                 checkport(offset, offset+n);
270                 for(p = a; port < offset+n; port++)
271                         *p++ = inb(port);
272                 return n;
273
274         case Qiow:
275                 if((n & 0x01) || (offset & 0x01))
276                         error(Ebadarg);
277                 checkport(offset, offset+n+1);
278                 n /= 2;
279                 sp = a;
280                 for(port = offset; port < offset+n; port += 2)
281                         *sp++ = ins(port);
282                 return n*2;
283
284         case Qiol:
285                 if((n & 0x03) || (offset & 0x03))
286                         error(Ebadarg);
287                 checkport(offset, offset+n+3);
288                 n /= 4;
289                 lp = a;
290                 for(port = offset; port < offset+n; port += 4)
291                         *lp++ = inl(port);
292                 return n*4;
293
294         case Qioalloc:
295                 break;
296
297         default:
298                 if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
299                         return fn(c, a, n, offset);
300                 error(Eperm);
301                 break;
302         }
303
304         offset = offset/Linelen;
305         n = n/Linelen;
306         p = a;
307         lock(&iomap);
308         for(m = iomap.m; n > 0 && m != nil; m = m->next){
309                 if(offset-- > 0)
310                         continue;
311                 if(strcmp(m->tag, "dummy") == 0)
312                         break;
313                 sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
314                 memmove(p, buf, Linelen);
315                 p += Linelen;
316                 n--;
317         }
318         unlock(&iomap);
319
320         return p - (char*)a;
321 }
322
323 static long
324 archwrite(Chan *c, void *a, long n, vlong offset)
325 {
326         char *p;
327         int port;
328         ushort *sp;
329         ulong *lp;
330         Rdwrfn *fn;
331
332         switch((ulong)c->qid.path){
333
334         case Qiob:
335                 p = a;
336                 checkport(offset, offset+n);
337                 for(port = offset; port < offset+n; port++)
338                         outb(port, *p++);
339                 return n;
340
341         case Qiow:
342                 if((n & 01) || (offset & 01))
343                         error(Ebadarg);
344                 checkport(offset, offset+n+1);
345                 n /= 2;
346                 sp = a;
347                 for(port = offset; port < offset+n; port += 2)
348                         outs(port, *sp++);
349                 return n*2;
350
351         case Qiol:
352                 if((n & 0x03) || (offset & 0x03))
353                         error(Ebadarg);
354                 checkport(offset, offset+n+3);
355                 n /= 4;
356                 lp = a;
357                 for(port = offset; port < offset+n; port += 4)
358                         outl(port, *lp++);
359                 return n*4;
360
361         default:
362                 if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
363                         return fn(c, a, n, offset);
364                 error(Eperm);
365                 break;
366         }
367         return 0;
368 }
369
370 Dev archdevtab = {
371         'P',
372         "arch",
373
374         devreset,
375         devinit,        
376         devshutdown,
377         archattach,
378         archwalk,
379         archstat,
380         archopen,
381         devcreate,
382         archclose,
383         archread,
384         devbread,
385         archwrite,
386         devbwrite,
387         devremove,
388         devwstat,
389 };
390
391 PCArch* arch;
392 extern PCArch* knownarch[];
393
394 PCArch archgeneric = {
395         "generic",                              /* id */
396         0,                                      /* ident */
397
398         0,                                      /* coreinit */
399         0,                                      /* coredetach */
400 };
401
402 static char     *sysnames[] =
403 {
404 [1]             "Alpha Demo. Unit",
405 [2]             "DEC 4000; Cobra",
406 [3]             "DEC 7000; Ruby",
407 [4]             "DEC 3000/500; Flamingo family (TC)",
408 [6]             "DEC 2000/300; Jensen (EISA/ISA)",
409 [7]             "DEC 3000/300; Pelican (TC)",
410 [8]             "Avalon A12; Avalon Multicomputer",
411 [9]             "DEC 2100/A500; Sable",
412 [10]            "DEC APXVME/64; AXPvme (VME?)",
413 [11]            "DEC AXPPCI/33; NoName (PCI/ISA)",
414 [12]            "DEC 21000; TurboLaser (PCI/EISA)",
415 [13]            "DEC 2100/A50; Avanti (PCI/ISA)",
416 [14]            "DEC MUSTANG; Mustang",
417 [15]            "DEC KN20AA; kn20aa (PCI/EISA)",
418 [17]            "DEC 1000; Mikasa (PCI/ISA?)",
419 [19]            "EB66; EB66 (PCI/ISA?)",                // DEC?
420 [20]            "EB64P; EB64+ (PCI/ISA?)",              // DEC?
421 [21]            "Alphabook1; Alphabook",
422 [22]            "DEC 4100; Rawhide (PCI/EISA)",
423 [23]            "DEC EV45/PBP; Lego",
424 [24]            "DEC 2100A/A500; Lynx",
425 [26]            "DEC AlphaPC 164",      // only supported one: "EB164 (PCI/ISA)"
426 [27]            "DEC 1000A; Noritake",
427 [28]            "DEC AlphaVME/224; Cortex",
428 [30]            "DEC 550; Miata (PCI/ISA)",
429 [32]            "DEC EV56/PBP; Takara",
430 [33]            "DEC AlphaVME/320; Yukon (VME?)",
431 [34]            "DEC 6600; MonetGoldrush",
432 // 200 and up is Alpha Processor Inc. machines
433 // [201]        "API UP1000; Nautilus",
434 };
435
436 static char     *cpunames[] =
437 {
438 [1]             "EV3",
439 [2]             "EV4: 21064",
440 [3]             "Simulation",
441 [4]             "LCA4: 2106[68]",
442 [5]             "EV5: 21164",
443 [6]             "EV45: 21064A",
444 [7]             "21164A",               /* only supported one: EV56 */
445 [8]             "EV6: 21264",
446 [9]             "PCA256: 21164PC",
447 };
448
449 void
450 cpuidprint(void)
451 {
452         int i, maj, min;
453         Hwcpu *cpu;
454         Hwdsr *dsr;
455         char *s;
456
457         print("\n");
458
459         if (hwrpb->rev >= 6) {
460                 dsr = (Hwdsr*)((ulong)hwrpb + hwrpb->dsroff);
461
462                 s = (char*)dsr + dsr->sysnameoff + 8;
463                 print("%s\n", s);
464         }
465         else {
466                 s = "<unknown>";
467                 if (hwrpb->systype < nelem(sysnames))
468                         s = sysnames[hwrpb->systype];
469                 print("%s (%llux, %llux, %llux)\n", s, hwrpb->systype, hwrpb->sysvar, hwrpb->sysrev);
470         }
471
472         for (i = 0; i < hwrpb->ncpu; i++) {
473                 cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff + i*hwrpb->cpulen);
474                 s = "<unknown>";
475                 maj = (ulong)cpu->cputype;
476                 min = (ulong)(cpu->cputype>>32);
477                 if (maj < nelem(cpunames))
478                         s = cpunames[maj];
479                 print("cpu%d: %s-%d (%d.%d, %llux, %llux)\n",
480                         i, s, min, maj, min, cpu->cpuvar, cpu->cpurev);
481         }
482
483         print("\n");
484 }
485
486 static long
487 cputyperead(Chan*, void *a, long n, vlong offset)
488 {
489         char str[32], *cputype;
490         ulong mhz, maj;
491         Hwcpu *cpu;
492
493         mhz = (m->cpuhz+999999)/1000000;
494         cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff);  /* NB CPU 0 */
495         cputype = "unknown";
496         maj = (ulong)cpu->cputype;
497         if (maj < nelem(cpunames))
498                 cputype = cpunames[maj];
499
500         snprint(str, sizeof(str), "%s %lud\n", cputype, mhz);
501         return readstr(offset, a, n, str);
502 }
503
504 void
505 archinit(void)
506 {
507         PCArch **p;
508
509         arch = 0;
510         for(p = knownarch; *p; p++){
511                 if((*p)->ident && (*p)->ident() == 0){
512                         arch = *p;
513                         break;
514                 }
515         }
516         if(arch == 0)
517                 arch = &archgeneric;
518
519         addarchfile("cputype", 0444, cputyperead, nil);
520 }
521
522 int
523 pcmspecial(char *idstr, ISAConf *isa)
524 {
525         return (_pcmspecial  != nil)? _pcmspecial(idstr, isa): -1;
526 }
527
528 void
529 pcmspecialclose(int a)
530 {
531         if (_pcmspecialclose != nil)
532                 _pcmspecialclose(a);
533 }