FreeBSD/Linux Kernel Cross Reference
sys/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 }
Cache object: e4b91f38cd0d9e6ef59b5495526c4b4e
|