]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/teg2/pci.c
usbehci: catch interrupt in tsleep
[plan9front.git] / sys / src / 9 / teg2 / pci.c
1 /*
2  * PCI support code.
3  * Needs a massive rewrite.
4  */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11
12 #define DBG     if(0) pcilog
13
14 typedef struct Pci Pci;
15
16 struct
17 {
18         char    output[16*1024];
19         int     ptr;
20 }PCICONS;
21
22 int
23 pcilog(char *fmt, ...)
24 {
25         int n;
26         va_list arg;
27         char buf[PRINTSIZE];
28
29         va_start(arg, fmt);
30         n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
31         va_end(arg);
32
33         memmove(PCICONS.output+PCICONS.ptr, buf, n);
34         PCICONS.ptr += n;
35         return n;
36 }
37
38 enum
39 {
40         MaxFNO          = 7,
41         MaxUBN          = 255,
42 };
43
44 enum
45 {                                       /* command register */
46         IOen            = (1<<0),
47         MEMen           = (1<<1),
48         MASen           = (1<<2),
49         MemWrInv        = (1<<4),
50         PErrEn          = (1<<6),
51         SErrEn          = (1<<8),
52 };
53
54 typedef struct {
55         ulong   cap;
56         ulong   ctl;
57 } Capctl;
58 typedef struct {
59         Capctl  dev;
60         Capctl  link;
61         Capctl  slot;
62 } Devlinkslot;
63
64 /* capability list id 0x10 is pci-e */
65 struct Pci {
66         /* pci-compatible config */
67         /* what io.h calls type 0 & type 1 pre-defined header */
68         ulong   id;
69         ulong   cs;
70         ulong   revclass;
71         ulong   misc;   /* cache line size, latency timer, header type, bist */
72         ulong   bar[2];         /* always 0 on tegra 2 */
73
74         /* types 1 & 2 pre-defined header */
75         ulong   bus;
76         ulong   ioaddrs;
77         ulong   memaddrs;
78         ulong   prefmem;
79         ulong   prefbasehi;
80         ulong   preflimhi;
81         /* type 2 pre-defined header only */
82         ulong   ioaddrhi;
83         ulong   cfgcapoff;      /* offset in cfg. space to cap. list (0x40) */
84         ulong   rom;
85         ulong   intr;           /* PciINT[LP] */
86         /* subsystem capability regs */
87         ulong   subsysid;
88         ulong   subsyscap;
89         /* */
90
91         Capctl  pwrmgmt;
92
93         /* msi */
94         ulong   msictlcap;
95         ulong   msimsgaddr[2];  /* little-endian */
96         ulong   msimsgdata;
97
98         /* pci-e cap. */
99         uchar   _pad0[0x80-0x60];
100         ulong   pciecap;
101         Devlinkslot port0;
102         ulong   rootctl;
103         ulong   rootsts;
104         Devlinkslot port1;
105
106         /* 0xbc */
107         
108 };
109
110 enum {
111         /* offsets from soc.pci */
112         Port0           = 0,
113         Port1           = 0x1000,
114         Pads            = 0x3000,
115         Afi             = 0x3800,
116         Aficfg          = Afi + 0xac,
117         Cfgspace        = 0x4000,
118         Ecfgspace       = 0x104000,
119
120         /* cs bits */
121         Iospace         = 1<<0,
122         Memspace        = 1<<1,
123         Busmaster       = 1<<2,
124
125         /* Aficfg bits */
126         Fpcion          = 1<<0,
127 };
128
129 struct Pcictlr {
130         union {
131                 uchar   _padpci[0x1000];
132                 Pci;
133         } ports[2];
134         uchar   _padpads[0x1000];
135         uchar   pads[0x800];
136         uchar   afi[0x800];
137         ulong   cfg[0x1000];
138         ulong   extcfg[0x1000];
139 };
140
141 static Lock pcicfglock;
142 static Lock pcicfginitlock;
143 static int pcicfgmode = -1;
144 static int pcimaxbno = 1;  /* was 7; only 2 pci buses; touching 3rd hangs */
145 static int pcimaxdno;
146 static Pcidev* pciroot;
147 static Pcidev* pcilist;
148 static Pcidev* pcitail;
149
150 static int pcicfgrw8(int, int, int, int);
151 static int pcicfgrw16(int, int, int, int);
152 static int pcicfgrw32(int, int, int, int);
153
154 static char* bustypes[] = {
155         "CBUSI",
156         "CBUSII",
157         "EISA",
158         "FUTURE",
159         "INTERN",
160         "ISA",
161         "MBI",
162         "MBII",
163         "MCA",
164         "MPI",
165         "MPSA",
166         "NUBUS",
167         "PCI",
168         "PCMCIA",
169         "TC",
170         "VL",
171         "VME",
172         "XPRESS",
173 };
174
175 static int
176 tbdffmt(Fmt* fmt)
177 {
178         char *p;
179         int l, r;
180         uint type, tbdf;
181
182         if((p = malloc(READSTR)) == nil)
183                 return fmtstrcpy(fmt, "(tbdfconv)");
184
185         switch(fmt->r){
186         case 'T':
187                 tbdf = va_arg(fmt->args, int);
188                 if(tbdf == BUSUNKNOWN)
189                         snprint(p, READSTR, "unknown");
190                 else{
191                         type = BUSTYPE(tbdf);
192                         if(type < nelem(bustypes))
193                                 l = snprint(p, READSTR, bustypes[type]);
194                         else
195                                 l = snprint(p, READSTR, "%d", type);
196                         snprint(p+l, READSTR-l, ".%d.%d.%d",
197                                 BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
198                 }
199                 break;
200
201         default:
202                 snprint(p, READSTR, "(tbdfconv)");
203                 break;
204         }
205         r = fmtstrcpy(fmt, p);
206         free(p);
207
208         return r;
209 }
210
211 ulong
212 pcibarsize(Pcidev *p, int rno)
213 {
214         ulong v, size;
215
216         v = pcicfgrw32(p->tbdf, rno, 0, 1);
217         pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
218         size = pcicfgrw32(p->tbdf, rno, 0, 1);
219         if(v & 1)
220                 size |= 0xFFFF0000;
221         pcicfgrw32(p->tbdf, rno, v, 0);
222
223         return -(size & ~0x0F);
224 }
225
226 static int
227 pcilscan(int bno, Pcidev** list)
228 {
229         Pcidev *p, *head, *tail;
230         int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
231
232         maxubn = bno;
233         head = nil;
234         tail = nil;
235         for(dno = 0; dno <= pcimaxdno; dno++){
236                 maxfno = 0;
237                 for(fno = 0; fno <= maxfno; fno++){
238                         /*
239                          * For this possible device, form the
240                          * bus+device+function triplet needed to address it
241                          * and try to read the vendor and device ID.
242                          * If successful, allocate a device struct and
243                          * start to fill it in with some useful information
244                          * from the device's configuration space.
245                          */
246                         tbdf = MKBUS(BusPCI, bno, dno, fno);
247                         l = pcicfgrw32(tbdf, PciVID, 0, 1);
248                         if(l == 0xFFFFFFFF || l == 0)
249                                 continue;
250                         p = malloc(sizeof(*p));
251                         if(p == nil)
252                                 panic("pcilscan: no memory");
253                         p->tbdf = tbdf;
254                         p->vid = l;
255                         p->did = l>>16;
256
257                         if(pcilist != nil)
258                                 pcitail->list = p;
259                         else
260                                 pcilist = p;
261                         pcitail = p;
262
263                         p->pcr = pcicfgr16(p, PciPCR);
264                         p->rid = pcicfgr8(p, PciRID);
265                         p->ccrp = pcicfgr8(p, PciCCRp);
266                         p->ccru = pcicfgr8(p, PciCCRu);
267                         p->ccrb = pcicfgr8(p, PciCCRb);
268                         p->cls = pcicfgr8(p, PciCLS);
269                         p->ltr = pcicfgr8(p, PciLTR);
270
271                         p->intl = pcicfgr8(p, PciINTL);
272
273                         /*
274                          * If the device is a multi-function device adjust the
275                          * loop count so all possible functions are checked.
276                          */
277                         hdt = pcicfgr8(p, PciHDT);
278                         if(hdt & 0x80)
279                                 maxfno = MaxFNO;
280
281                         /*
282                          * If appropriate, read the base address registers
283                          * and work out the sizes.
284                          */
285                         switch(p->ccrb) {
286                         case 0x03:              /* display controller */
287                                 /* fall through */
288                         case 0x01:              /* mass storage controller */
289                         case 0x02:              /* network controller */
290                         case 0x04:              /* multimedia device */
291                         case 0x07:              /* simple comm. controllers */
292                         case 0x08:              /* base system peripherals */
293                         case 0x09:              /* input devices */
294                         case 0x0A:              /* docking stations */
295                         case 0x0B:              /* processors */
296                         case 0x0C:              /* serial bus controllers */
297                                 if((hdt & 0x7F) != 0)
298                                         break;
299                                 rno = PciBAR0 - 4;
300                                 for(i = 0; i < nelem(p->mem); i++) {
301                                         rno += 4;
302                                         p->mem[i].bar = pcicfgr32(p, rno);
303                                         p->mem[i].size = pcibarsize(p, rno);
304                                 }
305                                 break;
306
307                         case 0x00:
308                         case 0x05:              /* memory controller */
309                         case 0x06:              /* bridge device */
310                         default:
311                                 break;
312                         }
313
314                         if(head != nil)
315                                 tail->link = p;
316                         else
317                                 head = p;
318                         tail = p;
319                 }
320         }
321
322         *list = head;
323         for(p = head; p != nil; p = p->link){
324                 /*
325                  * Find PCI-PCI bridges and recursively descend the tree.
326                  */
327                 if(p->ccrb != 0x06 || p->ccru != 0x04)
328                         continue;
329
330                 /*
331                  * If the secondary or subordinate bus number is not
332                  * initialised try to do what the PCI BIOS should have
333                  * done and fill in the numbers as the tree is descended.
334                  * On the way down the subordinate bus number is set to
335                  * the maximum as it's not known how many buses are behind
336                  * this one; the final value is set on the way back up.
337                  */
338                 sbn = pcicfgr8(p, PciSBN);
339                 ubn = pcicfgr8(p, PciUBN);
340
341                 if(sbn == 0 || ubn == 0) {
342                         sbn = maxubn+1;
343                         /*
344                          * Make sure memory, I/O and master enables are
345                          * off, set the primary, secondary and subordinate
346                          * bus numbers and clear the secondary status before
347                          * attempting to scan the secondary bus.
348                          *
349                          * Initialisation of the bridge should be done here.
350                          */
351                         pcicfgw32(p, PciPCR, 0xFFFF0000);
352                         l = (MaxUBN<<16)|(sbn<<8)|bno;
353                         pcicfgw32(p, PciPBN, l);
354                         pcicfgw16(p, PciSPSR, 0xFFFF);
355                         maxubn = pcilscan(sbn, &p->bridge);
356                         l = (maxubn<<16)|(sbn<<8)|bno;
357
358                         pcicfgw32(p, PciPBN, l);
359                 }
360                 else {
361                         if(ubn > maxubn)
362                                 maxubn = ubn;
363                         pcilscan(sbn, &p->bridge);
364                 }
365         }
366
367         return maxubn;
368 }
369
370 extern void rtl8169interrupt(Ureg*, void* arg);
371
372 /* not used yet */
373 static void
374 pciintr(Ureg *ureg, void *p)
375 {
376         rtl8169interrupt(ureg, p);              /* HACK */
377 }
378
379 static void
380 pcicfginit(void)
381 {
382         char *p;
383         Pci *pci = (Pci *)soc.pci;
384         Pcidev **list;
385         int bno, n;
386
387         lock(&pcicfginitlock);
388         if(pcicfgmode != -1) {
389                 unlock(&pcicfginitlock);
390                 return;
391         }
392
393         /*
394          * TrimSlice # pci 0 1
395          * Scanning PCI devices on bus 0 1
396          * BusDevFun  VendorId   DeviceId   Device Class       Sub-Class
397          * _____________________________________________________________
398          * 00.00.00   0x10de     0x0bf0     Bridge device           0x04
399          * 01.00.00   0x10ec     0x8168     Network controller      0x00
400          *
401          * thus pci bus 0 has a bridge with, perhaps, an ide/sata ctlr behind,
402          * and pci bus 1 has the realtek 8169 on it:
403          *
404          * TrimSlice # pci 1 long
405          * Scanning PCI devices on bus 1
406          *
407          * Found PCI device 01.00.00:
408          *   vendor ID =                   0x10ec
409          *   device ID =                   0x8168
410          *   command register =            0x0007
411          *   status register =             0x0010
412          *   revision ID =                 0x03
413          *   class code =                  0x02 (Network controller)
414          *   sub class code =              0x00
415          *   programming interface =       0x00
416          *   cache line =                  0x08
417          *   base address 0 =              0x80400001           config
418          *   base address 1 =              0x00000000           (ext. config)
419          *   base address 2 =              0xa000000c           "downstream"
420          *   base address 3 =              0x00000000           (prefetchable)
421          *   base address 4 =              0xa000400c           not "
422          *   base address 5 =              0x00000000           (unused)
423          */
424         n = pci->id >> 16;
425         if (((pci->id & MASK(16)) != Vnvidia || (n != 0xbf0 && n != 0xbf1)) &&
426              (pci->id & MASK(16)) != Vrealtek) {
427                 print("no pci controller at %#p\n", pci);
428                 unlock(&pcicfginitlock);
429                 return;
430         }
431         if (0)
432                 iprint("pci: %#p: nvidia, rev %#ux class %#6.6lux misc %#8.8lux\n",
433                         pci, (uchar)pci->revclass, pci->revclass >> 8,
434                         pci->misc);
435
436         pci->cs &= Iospace;
437         pci->cs |= Memspace | Busmaster;
438         coherence();
439
440         pcicfgmode = 1;
441 //      pcimaxdno = 31;
442         pcimaxdno = 15;                 /* for trimslice */
443
444         fmtinstall('T', tbdffmt);
445
446         if(p = getconf("*pcimaxbno")){
447                 n = strtoul(p, 0, 0);
448                 if(n < pcimaxbno)
449                         pcimaxbno = n;
450         }
451         if(p = getconf("*pcimaxdno")){
452                 n = strtoul(p, 0, 0);
453                 if(n < pcimaxdno)
454                         pcimaxdno = n;
455         }
456
457         list = &pciroot;
458         /* was bno = 0; trimslice needs to start at 1 */
459         for(bno = 1; bno <= pcimaxbno; bno++) {
460                 bno = pcilscan(bno, list);
461                 while(*list)
462                         list = &(*list)->link;
463         }
464         unlock(&pcicfginitlock);
465
466         if(getconf("*pcihinv"))
467                 pcihinv(nil);
468 }
469
470 enum {
471         Afiintrcode     = 0xb8,
472 };
473
474 void
475 pcieintrdone(void)                              /* dismiss pci-e intr */
476 {
477         ulong *afi;
478
479         afi = (ulong *)(soc.pci + Afi);
480         afi[Afiintrcode/sizeof *afi] = 0;       /* magic */
481         coherence();
482 }
483
484 /*
485  * whole config space for tbdf should be at (return address - rno).
486  */
487 static void *
488 tegracfgaddr(int tbdf, int rno)
489 {
490         uintptr addr;
491
492         addr = soc.pci + (rno < 256? Cfgspace: Ecfgspace) + BUSBDF(tbdf) + rno;
493 //      if (BUSBNO(tbdf) == 1)
494 //              addr += Port1;
495         return (void *)addr;
496 }
497
498 static int
499 pcicfgrw8(int tbdf, int rno, int data, int read)
500 {
501         int x;
502         void *addr;
503
504         if(pcicfgmode == -1)
505                 pcicfginit();
506
507         x = -1;
508         if(BUSDNO(tbdf) > pcimaxdno)
509                 return x;
510
511         addr = tegracfgaddr(tbdf, rno);
512
513         lock(&pcicfglock);
514         if(read)
515                 x = *(uchar *)addr;
516         else
517                 *(uchar *)addr = data;
518         unlock(&pcicfglock);
519
520         return x;
521 }
522
523 int
524 pcicfgr8(Pcidev* pcidev, int rno)
525 {
526         return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
527 }
528
529 void
530 pcicfgw8(Pcidev* pcidev, int rno, int data)
531 {
532         pcicfgrw8(pcidev->tbdf, rno, data, 0);
533 }
534
535 static int
536 pcicfgrw16(int tbdf, int rno, int data, int read)
537 {
538         int x;
539         void *addr;
540
541         if(pcicfgmode == -1)
542                 pcicfginit();
543
544         x = -1;
545         if(BUSDNO(tbdf) > pcimaxdno)
546                 return x;
547
548         addr = tegracfgaddr(tbdf, rno);
549
550         lock(&pcicfglock);
551         if(read)
552                 x = *(ushort *)addr;
553         else
554                 *(ushort *)addr = data;
555         unlock(&pcicfglock);
556
557         return x;
558 }
559
560 int
561 pcicfgr16(Pcidev* pcidev, int rno)
562 {
563         return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
564 }
565
566 void
567 pcicfgw16(Pcidev* pcidev, int rno, int data)
568 {
569         pcicfgrw16(pcidev->tbdf, rno, data, 0);
570 }
571
572 static int
573 pcicfgrw32(int tbdf, int rno, int data, int read)
574 {
575         int x;
576         vlong v;
577         void *addr;
578
579         if(pcicfgmode == -1)
580                 pcicfginit();
581
582         x = -1;
583         if(BUSDNO(tbdf) > pcimaxdno)
584                 return x;
585
586         addr = tegracfgaddr(tbdf, rno);
587         v = probeaddr((uintptr)addr);
588         if (v < 0)
589                 return -1;
590
591         lock(&pcicfglock);
592         if(read)
593                 x = *(ulong *)addr;
594         else
595                 *(ulong *)addr = data;
596         unlock(&pcicfglock);
597
598         return x;
599 }
600
601 int
602 pcicfgr32(Pcidev* pcidev, int rno)
603 {
604         return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
605 }
606
607 void
608 pcicfgw32(Pcidev* pcidev, int rno, int data)
609 {
610         pcicfgrw32(pcidev->tbdf, rno, data, 0);
611 }
612
613 Pcidev*
614 pcimatch(Pcidev* prev, int vid, int did)
615 {
616         if(pcicfgmode == -1)
617                 pcicfginit();
618
619         if(prev == nil)
620                 prev = pcilist;
621         else
622                 prev = prev->list;
623
624         while(prev != nil){
625                 if((vid == 0 || prev->vid == vid)
626                 && (did == 0 || prev->did == did))
627                         break;
628                 prev = prev->list;
629         }
630         return prev;
631 }
632
633 Pcidev*
634 pcimatchtbdf(int tbdf)
635 {
636         Pcidev *pcidev;
637
638         if(pcicfgmode == -1)
639                 pcicfginit();
640
641         for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
642                 if(pcidev->tbdf == tbdf)
643                         break;
644         }
645         return pcidev;
646 }
647
648 static void
649 pcilhinv(Pcidev* p)
650 {
651         int i;
652         Pcidev *t;
653
654         if(p == nil) {
655                 putstrn(PCICONS.output, PCICONS.ptr);
656                 p = pciroot;
657                 print("bus dev type vid  did intl memory\n");
658         }
659         for(t = p; t != nil; t = t->link) {
660                 print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
661                         BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
662                         t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
663
664                 for(i = 0; i < nelem(p->mem); i++) {
665                         if(t->mem[i].size == 0)
666                                 continue;
667                         print("%d:%.8lux %d ", i,
668                                 t->mem[i].bar, t->mem[i].size);
669                 }
670                 if(t->bridge)
671                         print("->%d", BUSBNO(t->bridge->tbdf));
672                 print("\n");
673         }
674         while(p != nil) {
675                 if(p->bridge != nil)
676                         pcilhinv(p->bridge);
677                 p = p->link;
678         }
679 }
680
681 void
682 pcihinv(Pcidev* p)
683 {
684         if(pcicfgmode == -1)
685                 pcicfginit();
686         lock(&pcicfginitlock);
687         pcilhinv(p);
688         unlock(&pcicfginitlock);
689 }
690
691 void
692 pcireset(void)
693 {
694         Pcidev *p;
695
696         if(pcicfgmode == -1)
697                 pcicfginit();
698
699         for(p = pcilist; p != nil; p = p->list) {
700                 /* don't mess with the bridges */
701                 if(p->ccrb == 0x06)
702                         continue;
703                 pciclrbme(p);
704         }
705 }
706
707 void
708 pcisetioe(Pcidev* p)
709 {
710         p->pcr |= IOen;
711         pcicfgw16(p, PciPCR, p->pcr);
712 }
713
714 void
715 pciclrioe(Pcidev* p)
716 {
717         p->pcr &= ~IOen;
718         pcicfgw16(p, PciPCR, p->pcr);
719 }
720
721 void
722 pcisetbme(Pcidev* p)
723 {
724         p->pcr |= MASen;
725         pcicfgw16(p, PciPCR, p->pcr);
726 }
727
728 void
729 pciclrbme(Pcidev* p)
730 {
731         p->pcr &= ~MASen;
732         pcicfgw16(p, PciPCR, p->pcr);
733 }
734
735 void
736 pcisetmwi(Pcidev* p)
737 {
738         p->pcr |= MemWrInv;
739         pcicfgw16(p, PciPCR, p->pcr);
740 }
741
742 void
743 pciclrmwi(Pcidev* p)
744 {
745         p->pcr &= ~MemWrInv;
746         pcicfgw16(p, PciPCR, p->pcr);
747 }
748
749 static int
750 pcigetpmrb(Pcidev* p)
751 {
752         int ptr;
753
754         if(p->pmrb != 0)
755                 return p->pmrb;
756         p->pmrb = -1;
757
758         /*
759          * If there are no extended capabilities implemented,
760          * (bit 4 in the status register) assume there's no standard
761          * power management method.
762          * Find the capabilities pointer based on PCI header type.
763          */
764         if(!(pcicfgr16(p, PciPSR) & 0x0010))
765                 return -1;
766         switch(pcicfgr8(p, PciHDT)){
767         default:
768                 return -1;
769         case 0:                                 /* all other */
770         case 1:                                 /* PCI to PCI bridge */
771                 ptr = 0x34;
772                 break;
773         case 2:                                 /* CardBus bridge */
774                 ptr = 0x14;
775                 break;
776         }
777         ptr = pcicfgr32(p, ptr);
778
779         while(ptr != 0){
780                 /*
781                  * Check for validity.
782                  * Can't be in standard header and must be double
783                  * word aligned.
784                  */
785                 if(ptr < 0x40 || (ptr & ~0xFC))
786                         return -1;
787                 if(pcicfgr8(p, ptr) == 0x01){
788                         p->pmrb = ptr;
789                         return ptr;
790                 }
791
792                 ptr = pcicfgr8(p, ptr+1);
793         }
794
795         return -1;
796 }
797
798 int
799 pcigetpms(Pcidev* p)
800 {
801         int pmcsr, ptr;
802
803         if((ptr = pcigetpmrb(p)) == -1)
804                 return -1;
805
806         /*
807          * Power Management Register Block:
808          *  offset 0:   Capability ID
809          *         1:   next item pointer
810          *         2:   capabilities
811          *         4:   control/status
812          *         6:   bridge support extensions
813          *         7:   data
814          */
815         pmcsr = pcicfgr16(p, ptr+4);
816
817         return pmcsr & 0x0003;
818 }
819
820 int
821 pcisetpms(Pcidev* p, int state)
822 {
823         int ostate, pmc, pmcsr, ptr;
824
825         if((ptr = pcigetpmrb(p)) == -1)
826                 return -1;
827
828         pmc = pcicfgr16(p, ptr+2);
829         pmcsr = pcicfgr16(p, ptr+4);
830         ostate = pmcsr & 0x0003;
831         pmcsr &= ~0x0003;
832
833         switch(state){
834         default:
835                 return -1;
836         case 0:
837                 break;
838         case 1:
839                 if(!(pmc & 0x0200))
840                         return -1;
841                 break;
842         case 2:
843                 if(!(pmc & 0x0400))
844                         return -1;
845                 break;
846         case 3:
847                 break;
848         }
849         pmcsr |= state;
850         pcicfgw16(p, ptr+4, pmcsr);
851
852         return ostate;
853 }