]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/archacpi.c
archacpi: implement amldelay(), remove unused variable in setuplink()
[plan9front.git] / sys / src / 9 / pc / archacpi.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 #include <aml.h>
11
12 typedef struct Rsd Rsd;
13 typedef struct Tbl Tbl;
14
15 struct Rsd {
16         uchar   sig[8];
17         uchar   csum;
18         uchar   oemid[6];
19         uchar   rev;
20         uchar   raddr[4];
21         uchar   len[4];
22         uchar   xaddr[8];
23         uchar   xcsum;
24         uchar   reserved[3];
25 };
26
27 struct Tbl {
28         uchar   sig[4];
29         uchar   len[4];
30         uchar   rev;
31         uchar   csum;
32         uchar   oemid[6];
33         uchar   oemtid[8];
34         uchar   oemrev[4];
35         uchar   cid[4];
36         uchar   crev[4];
37         uchar   data[];
38 };
39
40 enum {
41         Tblsz   = 4+4+1+1+6+8+4+4+4,
42 };
43
44 static Rsd *rsd;
45
46 /* physical addresses visited by maptable() */
47 static int ntblpa;
48 static uintptr tblpa[64];
49
50 /* successfully mapped tables */
51 static int ntblmap;
52 static Tbl *tblmap[64];
53
54 static ushort
55 get16(uchar *p){
56         return p[1]<<8 | p[0];
57 }
58
59 static uint
60 get32(uchar *p){
61         return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
62 }
63
64 static uvlong
65 get64(uchar *p){
66         uvlong u;
67
68         u = get32(p+4);
69         return u<<32 | get32(p);
70 }
71
72 static uint
73 tbldlen(Tbl *t){
74         return get32(t->len) - Tblsz;
75 }
76
77 static void
78 maptable(uvlong xpa)
79 {
80         uchar *p, *e;
81         uintptr pa;
82         u32int l;
83         Tbl *t;
84         int i;
85
86         pa = xpa;
87         if((uvlong)pa != xpa || pa == 0)
88                 return;
89         if(ntblpa >= nelem(tblpa) || ntblmap >= nelem(tblmap))
90                 return;
91
92         for(i=0; i<ntblpa; i++){
93                 if(pa == tblpa[i])
94                         return;
95         }
96         tblpa[ntblpa++] = pa;
97
98         if((t = vmap(pa, 8)) == nil)
99                 return;
100         l = get32(t->len);
101         if(l < Tblsz){
102                 vunmap(t, 8);
103                 return;
104         }
105         vunmap(t, 8);
106         if((t = vmap(pa, l)) == nil)
107                 return;
108         if(checksum(t, l)){
109                 vunmap(t, l);
110                 return;
111         }
112         tblmap[ntblmap++] = t;
113
114         p = (uchar*)t;
115         e = p + l;
116         if(memcmp("RSDT", t->sig, 4) == 0){
117                 for(p = t->data; p+3 < e; p += 4)
118                         maptable(get32(p));
119                 return;
120         }
121         if(memcmp("XSDT", t->sig, 4) == 0){
122                 for(p = t->data; p+7 < e; p += 8)
123                         maptable(get64(p));
124                 return;
125         }
126         if(memcmp("FACP", t->sig, 4) == 0){
127                 if(l < 44)
128                         return;
129                 maptable(get32(p + 40));
130                 if(l < 148)
131                         return;
132                 maptable(get64(p + 140));
133                 return;
134         }
135 }
136
137 static void
138 maptables(void)
139 {
140         if(rsd == nil || ntblmap > 0 || ntblpa > 0)
141                 return;
142         if(!checksum(rsd, 20))
143                 maptable(get32(rsd->raddr));
144         if(rsd->rev >= 2)
145                 if(!checksum(rsd, 36))
146                         maptable(get64(rsd->xaddr));
147 }
148
149 static Apic*
150 findapic(int gsi, int *pintin)
151 {
152         Apic *a;
153         int i;
154
155         for(i=0; i<=MaxAPICNO; i++){
156                 if((a = mpioapic[i]) == nil)
157                         continue;
158                 if((a->flags & PcmpEN) == 0)
159                         continue;
160                 if(gsi >= a->gsibase && gsi <= a->gsibase+a->mre){
161                         if(pintin)
162                                 *pintin = gsi - a->gsibase;
163                         return a;
164                 }
165         }
166         print("findapic: no ioapic found for gsi %d\n", gsi);
167         return nil;
168 }
169
170 static void
171 addirq(int gsi, int type, int busno, int irq, int flags)
172 {
173         Apic *a;
174         Bus *bus;
175         Aintr *ai;
176         PCMPintr *pi;
177         int intin;
178
179         if((a = findapic(gsi, &intin)) == nil)
180                 return;
181
182         for(bus = mpbus; bus; bus = bus->next)
183                 if(bus->type == type && bus->busno == busno)
184                         goto Foundbus;
185
186         if((bus = xalloc(sizeof(Bus))) == nil)
187                 panic("addirq: no memory for Bus");
188         bus->busno = busno;
189         bus->type = type;
190         if(type == BusISA){
191                 bus->po = PcmpHIGH;
192                 bus->el = PcmpEDGE;
193                 if(mpisabus == -1)
194                         mpisabus = busno;
195         } else {
196                 bus->po = PcmpLOW;
197                 bus->el = PcmpLEVEL;
198         }
199         if(mpbus)
200                 mpbuslast->next = bus;
201         else
202                 mpbus = bus;
203         mpbuslast = bus;
204
205 Foundbus:
206         for(ai = bus->aintr; ai; ai = ai->next)
207                 if(ai->intr->irq == irq)
208                         return;
209
210         if((pi = xalloc(sizeof(PCMPintr))) == nil)
211                 panic("addirq: no memory for PCMPintr");
212         pi->type = PcmpIOINTR;
213         pi->intr = PcmpINT;
214         pi->flags = flags & (PcmpPOMASK|PcmpELMASK);
215         pi->busno = busno;
216         pi->irq = irq;
217         pi->apicno = a->apicno;
218         pi->intin = intin;
219
220         if((ai = xalloc(sizeof(Aintr))) == nil)
221                 panic("addirq: no memory for Aintr");
222         ai->intr = pi;
223         ai->apic = a;
224         ai->next = bus->aintr;
225         bus->aintr = ai;
226 }
227
228 static char*
229 eisaid(void *v)
230 {
231         static char id[8];
232         ulong b, l;
233         int i;
234
235         if(amltag(v) == 's')
236                 return v;
237         b = amlint(v);
238         for(l = 0, i=24; i>=0; i -= 8, b >>= 8)
239                 l |= (b & 0xFF) << i;
240         id[7] = 0;
241         for(i=6; i>=3; i--, l >>= 4)
242                 id[i] = "0123456789ABCDEF"[l & 0xF];
243         for(i=2; i>=0; i--, l >>= 5)
244                 id[i] = '@' + (l & 0x1F);
245         return id;
246 }
247
248 static int
249 pcibusno(void *dot)
250 {
251         int bno, adr, tbdf;
252         Pcidev *pdev;
253         void *p, *x;
254         char *id;
255
256         id = nil;
257         if((x = amlwalk(dot, "^_HID")) != nil)
258                 if((p = amlval(x)) != nil)
259                         id = eisaid(p);
260         if((x = amlwalk(dot, "^_BBN")) == nil)
261                 if((x = amlwalk(dot, "^_ADR")) == nil)
262                         return -1;
263         if((p = amlval(x)) == nil)
264                 return -1;
265         adr = amlint(p);
266         /* if root bridge, then we are done here */
267         if(id != nil && (strcmp(id, "PNP0A03")==0 || strcmp(id, "PNP0A08")==0))
268                 return adr;
269         x = amlwalk(dot, "^");
270         if(x == nil || x == dot)
271                 return -1;
272         if((bno = pcibusno(x)) < 0)
273                 return -1;
274         tbdf = MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
275         pdev = pcimatchtbdf(tbdf);
276         if(pdev == nil || pdev->bridge == nil)
277                 return -1;
278         return BUSBNO(pdev->bridge->tbdf);
279 }
280
281 static int
282 pciaddr(void *dot)
283 {
284         int adr, bno;
285         void *x;
286
287         for(;;){
288                 if((x = amlwalk(dot, "_ADR")) == nil){
289                         x = amlwalk(dot, "^");
290                         if(x == nil || x == dot)
291                                 break;
292                         dot = x;
293                         continue;
294                 }
295                 if((bno = pcibusno(x)) < 0)
296                         break;
297                 if((x = amlval(x)) == nil)
298                         break;
299                 adr = amlint(x);
300                 return MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
301         }
302         return -1;
303 }
304
305 static int
306 getirqs(void *d, uchar pmask[32], int *pflags)
307 {
308         int i, n, m;
309         uchar *p;
310
311         *pflags = 0;
312         memset(pmask, 0, 32);
313         if(amltag(d) != 'b')
314                 return -1;
315         p = amlval(d);
316         if(amllen(d) >= 2 && (p[0] == 0x22 || p[0] == 0x23)){
317                 pmask[0] = p[1];
318                 pmask[1] = p[2];
319                 if(amllen(d) >= 3 && p[0] == 0x23)
320                         *pflags = ((p[3] & (1<<0)) ? PcmpEDGE : PcmpLEVEL)
321                                 | ((p[3] & (1<<3)) ? PcmpLOW : PcmpHIGH);
322                 return 0;
323         }
324         if(amllen(d) >= 5 && p[0] == 0x89){
325                 n = p[4];
326                 if(amllen(d) < 5+n*4)
327                         return -1;
328                 for(i=0; i<n; i++){
329                         m = get32(p+5 + i*4);
330                         if(m >= 0 && m < 256)
331                                 pmask[m/8] |= 1<<(m%8);
332                 }
333                 *pflags = ((p[3] & (1<<1)) ? PcmpEDGE : PcmpLEVEL)
334                         | ((p[3] & (1<<2)) ? PcmpLOW : PcmpHIGH);
335                 return 0;
336         }
337         return -1;
338 }
339
340 static uchar*
341 setirq(void *d, uint irq)
342 {
343         uchar *p;
344
345         if(amltag(d) != 'b')
346                 return nil;
347         p = amlnew('b', amllen(d));
348         memmove(p, d, amllen(p));
349         if(p[0] == 0x22 || p[0] == 0x23){
350                 irq = 1<<irq;
351                 p[1] = irq;
352                 p[2] = irq>>8;
353         }
354         if(p[0] == 0x89){
355                 p[4] = 1;
356                 p[5] = irq;
357                 p[6] = irq>>8;
358                 p[7] = irq>>16;
359                 p[8] = irq>>24;
360         }
361         return p;
362 }
363
364 static int
365 setuplink(void *link, int *pflags)
366 {
367         uchar im, pm[32], cm[32], *c;
368         int gsi, gsi2, i;
369         void *r;
370
371         if(amltag(link) != 'N')
372                 return -1;
373
374         r = nil;
375         if(amleval(amlwalk(link, "_PRS"), "", &r) < 0)
376                 return -1;
377         if(getirqs(r, pm, pflags) < 0)
378                 return -1;
379
380         r = nil;
381         if(amleval(amlwalk(link, "_CRS"), "", &r) < 0)
382                 return -1;
383         if(getirqs(r, cm, pflags) < 0)
384                 return -1;
385         
386         gsi = gsi2 = -1;
387         print("setuplink: %N: EL=%s%s PO=%s%s INTIN=[ ", link, 
388                 (*pflags & PcmpELMASK) == PcmpEDGE ? "EDGE" : "",
389                 (*pflags & PcmpELMASK) == PcmpLEVEL ? "LEVEL" : "",
390                 (*pflags & PcmpPOMASK) == PcmpHIGH ? "HIGH" : "",
391                 (*pflags & PcmpPOMASK) == PcmpLOW ? "LOW" : "");
392         for(i=0; i<256; i++){
393                 im = 1<<(i%8);
394                 if(pm[i/8] & im){
395                         if(cm[i/8] & im){
396                                 gsi = i;
397                                 print("*");
398                         }
399                         print("%d ", i);
400                         gsi2 = i;
401                 }
402         }
403         print("]\n");
404
405         if(getconf("*nopcirouting") == nil)
406         if(gsi <= 0 && gsi2 > 0 && (c = setirq(r, gsi2)) != nil){
407                 if(amleval(amlwalk(link, "_SRS"), "b", c, nil) == 0){
408                         gsi = gsi2;
409                         print("setuplink: %N -> %d\n", link, gsi);
410                 }
411         }
412
413         return gsi;
414 }
415
416 static int
417 enumprt(void *dot, void *)
418 {
419         void *p, **a, **b;
420         int bno, dno, pin, gsi, flags;
421         int n, i;
422
423         bno = pcibusno(dot);
424         if(bno < 0)
425                 return 1;
426
427         /* evalulate _PRT method */
428         p = nil;
429         if(amleval(dot, "", &p) < 0)
430                 return 1;
431         if(amltag(p) != 'p')
432                 return 1;
433
434         amltake(p);
435         n = amllen(p);
436         a = amlval(p);
437         for(i=0; i<n; i++){
438                 if(amltag(a[i]) != 'p')
439                         continue;
440                 if(amllen(a[i]) != 4)
441                         continue;
442                 flags = 0;
443                 b = amlval(a[i]);
444                 dno = amlint(b[0])>>16;
445                 pin = amlint(b[1]);
446                 gsi = amlint(b[3]);
447                 if(gsi==0){
448                         gsi = setuplink(b[2], &flags);
449                         if(gsi <= 0)
450                                 continue;
451                 }
452                 addirq(gsi, BusPCI, bno, (dno<<2)|pin, flags);
453         }
454         amldrop(p);
455
456         return 1;
457 }
458
459 static void
460 acpiinit(void)
461 {
462         Tbl *t;
463         Apic *a;
464         void *va;
465         uchar *p, *e;
466         ulong lapicbase;
467         int machno, i, c;
468
469         maptables();
470
471         amlinit();
472
473         /* load DSDT */
474         for(i=0; i<ntblmap; i++){
475                 t = tblmap[i];
476                 if(memcmp(t->sig, "DSDT", 4) == 0){
477                         amlload(t->data, tbldlen(t));
478                         break;
479                 }
480         }
481
482         /* load SSDT, there can be multiple tables */
483         for(i=0; i<ntblmap; i++){
484                 t = tblmap[i];
485                 if(memcmp(t->sig, "SSDT", 4) == 0)
486                         amlload(t->data, tbldlen(t));
487         }
488
489         /* set APIC mode */
490         amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
491
492         for(i=0; i<ntblmap; i++){
493                 t = tblmap[i];
494                 if(memcmp(t->sig, "APIC", 4) == 0)
495                         goto Foundapic;
496         }
497         panic("acpiinit: no MADT (APIC) table");
498         return;
499
500 Foundapic:
501         p = t->data;
502         e = p + tbldlen(t);
503         lapicbase = get32(p); p += 8;
504         va = vmap(lapicbase, 1024);
505         print("LAPIC: %.8lux %.8lux\n", lapicbase, (ulong)va);
506         if(va == nil)
507                 panic("acpiinit: cannot map lapic %.8lux", lapicbase);
508
509         machno = 0;
510         for(; p < e; p += c){
511                 c = p[1];
512                 if(c < 2 || (p+c) > e)
513                         break;
514                 switch(*p){
515                 case 0x00:      /* Processor Local APIC */
516                         if(p[3] > MaxAPICNO)
517                                 break;
518                         if((a = xalloc(sizeof(Apic))) == nil)
519                                 panic("acpiinit: no memory for Apic");
520                         a->type = PcmpPROCESSOR;
521                         a->apicno = p[3];
522                         a->paddr = lapicbase;
523                         a->addr = va;
524                         a->lintr[0] = ApicIMASK;
525                         a->lintr[1] = ApicIMASK;
526                         a->flags = p[4] & PcmpEN;
527
528                         /* skip disabled processors */
529                         if((a->flags & PcmpEN) == 0 || mpapic[a->apicno] != nil){
530                                 xfree(a);
531                                 break;
532                         }
533                         a->machno = machno++;
534
535                         /*
536                          * platform firmware should list the boot processor
537                          * as the first processor entry in the MADT
538                          */
539                         if(a->machno == 0)
540                                 a->flags |= PcmpBP;
541
542                         mpapic[a->apicno] = a;
543                         break;
544                 case 0x01:      /* I/O APIC */
545                         if(p[2] > MaxAPICNO)
546                                 break;
547                         if((a = xalloc(sizeof(Apic))) == nil)
548                                 panic("acpiinit: no memory for io Apic");
549                         a->type = PcmpIOAPIC;
550                         a->apicno = p[2];
551                         a->paddr = get32(p+4);
552                         if((a->addr = vmap(a->paddr, 1024)) == nil)
553                                 panic("acpiinit: cannot map ioapic %.8lux", a->paddr);
554                         a->gsibase = get32(p+8);
555                         a->flags = PcmpEN;
556                         mpioapic[a->apicno] = a;
557                         ioapicinit(a, a->apicno);
558                         break;
559                 case 0x02:      /* Interrupt Source Override */
560                         addirq(get32(p+4), BusISA, 0, p[3], get16(p+8));
561                         break;
562                 case 0x03:      /* NMI Source */
563                 case 0x04:      /* Local APIC NMI */
564                 case 0x05:      /* Local APIC Address Override */
565                 case 0x06:      /* I/O SAPIC */
566                 case 0x07:      /* Local SAPIC */
567                 case 0x08:      /* Platform Interrupt Sources */
568                 case 0x09:      /* Processor Local x2APIC */
569                 case 0x0A:      /* x2APIC NMI */
570                 case 0x0B:      /* GIC */
571                 case 0x0C:      /* GICD */
572                         break;
573                 }
574         }
575
576         /* look for PCI interrupt mappings */
577         amlenum(amlroot, "_PRT", enumprt, nil);
578
579         /* add identity mapped legacy isa interrupts */
580         for(i=0; i<16; i++)
581                 addirq(i, BusISA, 0, i, 0);
582
583         /* free the AML interpreter */
584         amlexit();
585
586         /*
587          * Ininitalize local APIC and start application processors.
588          */
589         mpinit();
590 }
591
592 static int identify(void);
593
594 PCArch archacpi = {
595 .id=            "ACPI", 
596 .ident=         identify,
597 .reset=         mpshutdown,
598 .intrinit=      acpiinit,
599 .intrenable=    mpintrenable,
600 .intron=        lapicintron,
601 .introff=       lapicintroff,
602 .fastclock=     i8253read,
603 .timerset=      lapictimerset,
604 };
605
606 static long
607 readtbls(Chan*, void *v, long n, vlong o)
608 {
609         int i, l, m;
610         uchar *p;
611         Tbl *t;
612
613         maptables();
614
615         p = v;
616         for(i=0; n > 0 && i < ntblmap; i++){
617                 t = tblmap[i];
618                 l = get32(t->len);
619                 if(o >= l){
620                         o -= l;
621                         continue;
622                 }
623                 m = l - o;
624                 if(m > n)
625                         m = n;
626                 memmove(p, (uchar*)t + o, m);
627                 p += m;
628                 n -= m;
629                 o = 0;
630         }
631         return p - (uchar*)v;
632 }
633
634 static int
635 identify(void)
636 {
637         char *cp;
638
639         if((cp = getconf("*acpi")) == nil)
640                 return 1;
641         if((rsd = sigsearch("RSD PTR ")) == nil)
642                 return 1;
643         if(checksum(rsd, 20) && checksum(rsd, 36))
644                 return 1;
645         addarchfile("acpitbls", 0444, readtbls, nil);
646         if(strcmp(cp, "0") == 0)
647                 return 1;
648         if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
649                 return 1;
650         if(m->havetsc && getconf("*notsc") == nil)
651                 archacpi.fastclock = tscticks;
652         return 0;
653 }
654
655 static int
656 readpcicfg(Amlio *io, void *data, int n, int offset)
657 {
658         ulong r, x;
659         Pcidev *p;
660         uchar *a;
661         int i;
662
663         a = data;
664         p = io->aux;
665         if(p == nil)
666                 return -1;
667         offset += io->off;
668         if(offset > 256)
669                 return 0;
670         if(n+offset > 256)
671                 n = 256-offset;
672         r = offset;
673         if(!(r & 3) && n == 4){
674                 x = pcicfgr32(p, r);
675                 PBIT32(a, x);
676                 return 4;
677         }
678         if(!(r & 1) && n == 2){
679                 x = pcicfgr16(p, r);
680                 PBIT16(a, x);
681                 return 2;
682         }
683         for(i = 0; i <  n; i++){
684                 x = pcicfgr8(p, r);
685                 PBIT8(a, x);
686                 a++;
687                 r++;
688         }
689         return i;
690 }
691
692 static int
693 writepcicfg(Amlio *io, void *data, int n, int offset)
694 {
695         ulong r, x;
696         Pcidev *p;
697         uchar *a;
698         int i;
699
700         a = data;
701         p = io->aux;
702         if(p == nil)
703                 return -1;
704         offset += io->off;
705         if(offset > 256)
706                 return 0;
707         if(n+offset > 256)
708                 n = 256-offset;
709         r = offset;
710         if(!(r & 3) && n == 4){
711                 x = GBIT32(a);
712                 pcicfgw32(p, r, x);
713                 return 4;
714         }
715         if(!(r & 1) && n == 2){
716                 x = GBIT16(a);
717                 pcicfgw16(p, r, x);
718                 return 2;
719         }
720         for(i = 0; i <  n; i++){
721                 x = GBIT8(a);
722                 pcicfgw8(p, r, x);
723                 a++;
724                 r++;
725         }
726         return i;
727 }
728
729 static int
730 readioport(Amlio *io, void *data, int len, int port)
731 {
732         uchar *a;
733
734         a = data;
735         port += io->off;
736         switch(len){
737         case 4:
738                 PBIT32(a, inl(port));
739                 return 4;
740         case 2:
741                 PBIT16(a, ins(port));
742                 return 2;
743         case 1:
744                 PBIT8(a, inb(port));
745                 return 1;
746         }
747         return -1;
748 }
749
750 static int
751 writeioport(Amlio *io, void *data, int len, int port)
752 {
753         uchar *a;
754
755         a = data;
756         port += io->off;
757         switch(len){
758         case 4:
759                 outl(port, GBIT32(a));
760                 return 4;
761         case 2:
762                 outs(port, GBIT16(a));
763                 return 2;
764         case 1:
765                 outb(port, GBIT8(a));
766                 return 1;
767         }
768         return -1;
769 }
770
771 int
772 amlmapio(Amlio *io)
773 {
774         int tbdf;
775         Pcidev *pdev;
776         char buf[64];
777
778         switch(io->space){
779         default:
780                 print("amlmapio: address space %x not implemented\n", io->space);
781                 break;
782         case MemSpace:
783                 if((io->va = vmap(io->off, io->len)) == nil){
784                         print("amlmapio: vmap failed\n");
785                         break;
786                 }
787                 return 0;
788         case IoSpace:
789                 snprint(buf, sizeof(buf), "%N", io->name);
790                 if(ioalloc(io->off, io->len, 0, buf) < 0){
791                         print("amlmapio: ioalloc failed\n");
792                         break;
793                 }
794                 io->read = readioport;
795                 io->write = writeioport;
796                 return 0;
797         case PcicfgSpace:
798                 if((tbdf = pciaddr(io->name)) < 0){
799                         print("amlmapio: no address\n");
800                         break;
801                 }
802                 if((pdev = pcimatchtbdf(tbdf)) == nil){
803                         print("amlmapio: no device %T\n", tbdf);
804                         break;
805                 }
806                 io->aux = pdev;
807                 io->read = readpcicfg;
808                 io->write = writepcicfg;
809                 return 0;
810         }
811         print("amlmapio: mapping %N failed\n", io->name);
812         return -1;
813 }
814
815 void
816 amlunmapio(Amlio *io)
817 {
818         switch(io->space){
819         case MemSpace:
820                 vunmap(io->va, io->len);
821                 break;
822         case IoSpace:
823                 iofree(io->off);
824                 break;
825         }
826 }
827
828 void*
829 amlalloc(int n){
830         void *p;
831
832         if((p = malloc(n)) == nil)
833                 panic("amlalloc: no memory");
834         memset(p, 0, n);
835         return p;
836 }
837
838 void
839 amlfree(void *p){
840         free(p);
841 }
842
843 void
844 amldelay(int us)
845 {
846         microdelay(us);
847 }