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 struct 15 { 16 char output[PCICONSSIZE]; 17 int ptr; 18 }PCICONS; 19 20 int pcivga; 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 { /* configuration mechanism #1 */ 40 PciADDR = 0xCF8, /* CONFIG_ADDRESS */ 41 PciDATA = 0xCFC, /* CONFIG_DATA */ 42 43 /* configuration mechanism #2 */ 44 PciCSE = 0xCF8, /* configuration space enable */ 45 PciFORWARD = 0xCFA, /* which bus */ 46 47 MaxFNO = 7, 48 MaxUBN = 255, 49 }; 50 51 enum 52 { /* command register */ 53 IOen = (1<<0), 54 MEMen = (1<<1), 55 MASen = (1<<2), 56 MemWrInv = (1<<4), 57 PErrEn = (1<<6), 58 SErrEn = (1<<8), 59 }; 60 61 static Lock pcicfglock; 62 static Lock pcicfginitlock; 63 static int pcicfgmode = -1; 64 static int pcimaxbno = 7; 65 static int pcimaxdno; 66 static Pcidev* pciroot; 67 static Pcidev* pcilist; 68 static Pcidev* pcitail; 69 static int nobios, nopcirouting; 70 static BIOS32si* pcibiossi; 71 72 static int pcicfgrw8raw(int, int, int, int); 73 static int pcicfgrw16raw(int, int, int, int); 74 static int pcicfgrw32raw(int, int, int, int); 75 76 static int (*pcicfgrw8)(int, int, int, int) = pcicfgrw8raw; 77 static int (*pcicfgrw16)(int, int, int, int) = pcicfgrw16raw; 78 static int (*pcicfgrw32)(int, int, int, int) = pcicfgrw32raw; 79 80 static char* bustypes[] = { 81 "CBUSI", 82 "CBUSII", 83 "EISA", 84 "FUTURE", 85 "INTERN", 86 "ISA", 87 "MBI", 88 "MBII", 89 "MCA", 90 "MPI", 91 "MPSA", 92 "NUBUS", 93 "PCI", 94 "PCMCIA", 95 "TC", 96 "VL", 97 "VME", 98 "XPRESS", 99 }; 100 101 static int 102 tbdffmt(Fmt* fmt) 103 { 104 char *p; 105 int l, r; 106 uint type, tbdf; 107 108 if((p = malloc(READSTR)) == nil) 109 return fmtstrcpy(fmt, "(tbdfconv)"); 110 111 switch(fmt->r){ 112 case 'T': 113 tbdf = va_arg(fmt->args, int); 114 if(tbdf == BUSUNKNOWN) 115 snprint(p, READSTR, "unknown"); 116 else{ 117 type = BUSTYPE(tbdf); 118 if(type < nelem(bustypes)) 119 l = snprint(p, READSTR, bustypes[type]); 120 else 121 l = snprint(p, READSTR, "%d", type); 122 snprint(p+l, READSTR-l, ".%d.%d.%d", 123 BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); 124 } 125 break; 126 127 default: 128 snprint(p, READSTR, "(tbdfconv)"); 129 break; 130 } 131 r = fmtstrcpy(fmt, p); 132 free(p); 133 134 return r; 135 } 136 137 ulong 138 pcibarsize(Pcidev *p, int rno) 139 { 140 ulong v, size; 141 142 v = pcicfgrw32(p->tbdf, rno, 0, 1); 143 pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0); 144 size = pcicfgrw32(p->tbdf, rno, 0, 1); 145 if(v & 1) 146 size |= 0xFFFF0000; 147 pcicfgrw32(p->tbdf, rno, v, 0); 148 149 return -(size & ~0x0F); 150 } 151 152 static int 153 pcisizcmp(void *a, void *b) 154 { 155 Pcisiz *aa, *bb; 156 157 aa = a; 158 bb = b; 159 return aa->siz - bb->siz; 160 } 161 162 static ulong 163 pcimask(ulong v) 164 { 165 ulong m; 166 167 m = BI2BY*sizeof(v); 168 for(m = 1<<(m-1); m != 0; m >>= 1) { 169 if(m & v) 170 break; 171 } 172 173 m--; 174 if((v & m) == 0) 175 return v; 176 177 v |= m; 178 return v+1; 179 } 180 181 static void 182 pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg) 183 { 184 Pcidev *p; 185 int ntb, i, size, rno, hole; 186 ulong v, mema, ioa, sioa, smema, base, limit; 187 Pcisiz *table, *tptr, *mtb, *itb; 188 189 if(!nobios) 190 return; 191 192 ioa = *pioa; 193 mema = *pmema; 194 195 DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n", 196 wrreg, root->tbdf, mema, ioa); 197 198 ntb = 0; 199 for(p = root; p != nil; p = p->link) 200 ntb++; 201 202 ntb *= (PciCIS-PciBAR0)/4; 203 table = malloc(2*ntb*sizeof(Pcisiz)); 204 if(table == nil) 205 panic("pcibusmap: no memory"); 206 itb = table; 207 mtb = table+ntb; 208 209 /* 210 * Build a table of sizes 211 */ 212 for(p = root; p != nil; p = p->link) { 213 if(p->ccrb == 0x06) { 214 if(p->ccru != 0x04 || p->bridge == nil) { 215 // DBG("pci: ignored bridge %T\n", p->tbdf); 216 continue; 217 } 218 219 sioa = ioa; 220 smema = mema; 221 pcibusmap(p->bridge, &smema, &sioa, 0); 222 223 hole = pcimask(smema-mema); 224 if(hole < (1<<20)) 225 hole = 1<<20; 226 p->mema.size = hole; 227 228 hole = pcimask(sioa-ioa); 229 if(hole < (1<<12)) 230 hole = 1<<12; 231 232 p->ioa.size = hole; 233 234 itb->dev = p; 235 itb->bar = -1; 236 itb->siz = p->ioa.size; 237 itb++; 238 239 mtb->dev = p; 240 mtb->bar = -1; 241 mtb->siz = p->mema.size; 242 mtb++; 243 continue; 244 } 245 246 for(i = 0; i <= 5; i++) { 247 rno = PciBAR0 + i*4; 248 v = pcicfgrw32(p->tbdf, rno, 0, 1); 249 size = pcibarsize(p, rno); 250 if(size == 0) 251 continue; 252 253 if(v & 1) { 254 itb->dev = p; 255 itb->bar = i; 256 itb->siz = size; 257 itb++; 258 } 259 else { 260 mtb->dev = p; 261 mtb->bar = i; 262 mtb->siz = size; 263 mtb++; 264 } 265 266 p->mem[i].size = size; 267 } 268 } 269 270 /* 271 * Sort both tables IO smallest first, Memory largest 272 */ 273 qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp); 274 tptr = table+ntb; 275 qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp); 276 277 /* 278 * Allocate IO address space on this bus 279 */ 280 for(tptr = table; tptr < itb; tptr++) { 281 hole = tptr->siz; 282 if(tptr->bar == -1) 283 hole = 1<<12; 284 ioa = (ioa+hole-1) & ~(hole-1); 285 286 p = tptr->dev; 287 if(tptr->bar == -1) 288 p->ioa.bar = ioa; 289 else { 290 p->pcr |= IOen; 291 p->mem[tptr->bar].bar = ioa|1; 292 if(wrreg) 293 pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0); 294 } 295 296 ioa += tptr->siz; 297 } 298 299 /* 300 * Allocate Memory address space on this bus 301 */ 302 for(tptr = table+ntb; tptr < mtb; tptr++) { 303 hole = tptr->siz; 304 if(tptr->bar == -1) 305 hole = 1<<20; 306 mema = (mema+hole-1) & ~(hole-1); 307 308 p = tptr->dev; 309 if(tptr->bar == -1) 310 p->mema.bar = mema; 311 else { 312 p->pcr |= MEMen; 313 p->mem[tptr->bar].bar = mema; 314 if(wrreg) 315 pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0); 316 } 317 mema += tptr->siz; 318 } 319 320 *pmema = mema; 321 *pioa = ioa; 322 free(table); 323 324 if(wrreg == 0) 325 return; 326 327 /* 328 * Finally set all the bridge addresses & registers 329 */ 330 for(p = root; p != nil; p = p->link) { 331 if(p->bridge == nil) { 332 pcicfgrw8(p->tbdf, PciLTR, 64, 0); 333 334 p->pcr |= MASen; 335 pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0); 336 continue; 337 } 338 339 base = p->ioa.bar; 340 limit = base+p->ioa.size-1; 341 v = pcicfgrw32(p->tbdf, PciIBR, 0, 1); 342 v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8); 343 pcicfgrw32(p->tbdf, PciIBR, v, 0); 344 v = (limit & 0xFFFF0000)|(base>>16); 345 pcicfgrw32(p->tbdf, PciIUBR, v, 0); 346 347 base = p->mema.bar; 348 limit = base+p->mema.size-1; 349 v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16); 350 pcicfgrw32(p->tbdf, PciMBR, v, 0); 351 352 /* 353 * Disable memory prefetch 354 */ 355 pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0); 356 pcicfgrw8(p->tbdf, PciLTR, 64, 0); 357 358 /* 359 * Enable the bridge 360 */ 361 p->pcr |= IOen|MEMen|MASen; 362 pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0); 363 364 sioa = p->ioa.bar; 365 smema = p->mema.bar; 366 pcibusmap(p->bridge, &smema, &sioa, 1); 367 } 368 } 369 370 /* side effect: if a video controller is seen, set pcivga non-zero */ 371 static int 372 pcilscan(int bno, Pcidev** list) 373 { 374 Pcidev *p, *head, *tail; 375 int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn; 376 377 maxubn = bno; 378 head = nil; 379 tail = nil; 380 for(dno = 0; dno <= pcimaxdno; dno++){ 381 maxfno = 0; 382 for(fno = 0; fno <= maxfno; fno++){ 383 /* 384 * For this possible device, form the 385 * bus+device+function triplet needed to address it 386 * and try to read the vendor and device ID. 387 * If successful, allocate a device struct and 388 * start to fill it in with some useful information 389 * from the device's configuration space. 390 */ 391 tbdf = MKBUS(BusPCI, bno, dno, fno); 392 l = pcicfgrw32(tbdf, PciVID, 0, 1); 393 if(l == 0xFFFFFFFF || l == 0) 394 continue; 395 p = malloc(sizeof(*p)); 396 if(p == nil) 397 panic("pcilscan: no memory"); 398 p->tbdf = tbdf; 399 p->vid = l; 400 p->did = l>>16; 401 402 if(pcilist != nil) 403 pcitail->list = p; 404 else 405 pcilist = p; 406 pcitail = p; 407 408 p->pcr = pcicfgr16(p, PciPCR); 409 p->rid = pcicfgr8(p, PciRID); 410 p->ccrp = pcicfgr8(p, PciCCRp); 411 p->ccru = pcicfgr8(p, PciCCRu); 412 p->ccrb = pcicfgr8(p, PciCCRb); 413 p->cls = pcicfgr8(p, PciCLS); 414 p->ltr = pcicfgr8(p, PciLTR); 415 416 p->intl = pcicfgr8(p, PciINTL); 417 418 /* 419 * If the device is a multi-function device adjust the 420 * loop count so all possible functions are checked. 421 */ 422 hdt = pcicfgr8(p, PciHDT); 423 if(hdt & 0x80) 424 maxfno = MaxFNO; 425 426 /* 427 * If appropriate, read the base address registers 428 * and work out the sizes. 429 */ 430 switch(p->ccrb) { 431 case 0x03: /* display controller */ 432 pcivga = 1; 433 /* fall through */ 434 case 0x01: /* mass storage controller */ 435 case 0x02: /* network controller */ 436 case 0x04: /* multimedia device */ 437 case 0x07: /* simple comm. controllers */ 438 case 0x08: /* base system peripherals */ 439 case 0x09: /* input devices */ 440 case 0x0A: /* docking stations */ 441 case 0x0B: /* processors */ 442 case 0x0C: /* serial bus controllers */ 443 if((hdt & 0x7F) != 0) 444 break; 445 rno = PciBAR0 - 4; 446 for(i = 0; i < nelem(p->mem); i++) { 447 rno += 4; 448 p->mem[i].bar = pcicfgr32(p, rno); 449 p->mem[i].size = pcibarsize(p, rno); 450 } 451 break; 452 453 case 0x00: 454 case 0x05: /* memory controller */ 455 case 0x06: /* bridge device */ 456 default: 457 break; 458 } 459 460 if(head != nil) 461 tail->link = p; 462 else 463 head = p; 464 tail = p; 465 } 466 } 467 468 *list = head; 469 for(p = head; p != nil; p = p->link){ 470 /* 471 * Find PCI-PCI bridges and recursively descend the tree. 472 */ 473 if(p->ccrb != 0x06 || p->ccru != 0x04) 474 continue; 475 476 /* 477 * If the secondary or subordinate bus number is not 478 * initialised try to do what the PCI BIOS should have 479 * done and fill in the numbers as the tree is descended. 480 * On the way down the subordinate bus number is set to 481 * the maximum as it's not known how many buses are behind 482 * this one; the final value is set on the way back up. 483 */ 484 sbn = pcicfgr8(p, PciSBN); 485 ubn = pcicfgr8(p, PciUBN); 486 487 if(sbn == 0 || ubn == 0 || nobios) { 488 sbn = maxubn+1; 489 /* 490 * Make sure memory, I/O and master enables are 491 * off, set the primary, secondary and subordinate 492 * bus numbers and clear the secondary status before 493 * attempting to scan the secondary bus. 494 * 495 * Initialisation of the bridge should be done here. 496 */ 497 pcicfgw32(p, PciPCR, 0xFFFF0000); 498 l = (MaxUBN<<16)|(sbn<<8)|bno; 499 pcicfgw32(p, PciPBN, l); 500 pcicfgw16(p, PciSPSR, 0xFFFF); 501 maxubn = pcilscan(sbn, &p->bridge); 502 l = (maxubn<<16)|(sbn<<8)|bno; 503 504 pcicfgw32(p, PciPBN, l); 505 } 506 else { 507 if(ubn > maxubn) 508 maxubn = ubn; 509 pcilscan(sbn, &p->bridge); 510 } 511 } 512 513 return maxubn; 514 } 515 516 int 517 pciscan(int bno, Pcidev **list) 518 { 519 int ubn; 520 521 lock(&pcicfginitlock); 522 ubn = pcilscan(bno, list); 523 unlock(&pcicfginitlock); 524 return ubn; 525 } 526 527 static uchar 528 pIIxget(Pcidev *router, uchar link) 529 { 530 uchar pirq; 531 532 /* link should be 0x60, 0x61, 0x62, 0x63 */ 533 pirq = pcicfgr8(router, link); 534 return (pirq < 16)? pirq: 0; 535 } 536 537 static void 538 pIIxset(Pcidev *router, uchar link, uchar irq) 539 { 540 pcicfgw8(router, link, irq); 541 } 542 543 static uchar 544 viaget(Pcidev *router, uchar link) 545 { 546 uchar pirq; 547 548 /* link should be 1, 2, 3, 5 */ 549 pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0; 550 551 return (link & 1)? (pirq >> 4): (pirq & 15); 552 } 553 554 static void 555 viaset(Pcidev *router, uchar link, uchar irq) 556 { 557 uchar pirq; 558 559 pirq = pcicfgr8(router, 0x55 + (link >> 1)); 560 pirq &= (link & 1)? 0x0f: 0xf0; 561 pirq |= (link & 1)? (irq << 4): (irq & 15); 562 pcicfgw8(router, 0x55 + (link>>1), pirq); 563 } 564 565 static uchar 566 optiget(Pcidev *router, uchar link) 567 { 568 uchar pirq = 0; 569 570 /* link should be 0x02, 0x12, 0x22, 0x32 */ 571 if ((link & 0xcf) == 0x02) 572 pirq = pcicfgr8(router, 0xb8 + (link >> 5)); 573 return (link & 0x10)? (pirq >> 4): (pirq & 15); 574 } 575 576 static void 577 optiset(Pcidev *router, uchar link, uchar irq) 578 { 579 uchar pirq; 580 581 pirq = pcicfgr8(router, 0xb8 + (link >> 5)); 582 pirq &= (link & 0x10)? 0x0f : 0xf0; 583 pirq |= (link & 0x10)? (irq << 4): (irq & 15); 584 pcicfgw8(router, 0xb8 + (link >> 5), pirq); 585 } 586 587 static uchar 588 aliget(Pcidev *router, uchar link) 589 { 590 /* No, you're not dreaming */ 591 static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; 592 uchar pirq; 593 594 /* link should be 0x01..0x08 */ 595 pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); 596 return (link & 1)? map[pirq&15]: map[pirq>>4]; 597 } 598 599 static void 600 aliset(Pcidev *router, uchar link, uchar irq) 601 { 602 /* Inverse of map in aliget */ 603 static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; 604 uchar pirq; 605 606 pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); 607 pirq &= (link & 1)? 0x0f: 0xf0; 608 pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15); 609 pcicfgw8(router, 0x48 + ((link-1)>>1), pirq); 610 } 611 612 static uchar 613 cyrixget(Pcidev *router, uchar link) 614 { 615 uchar pirq; 616 617 /* link should be 1, 2, 3, 4 */ 618 pirq = pcicfgr8(router, 0x5c + ((link-1)>>1)); 619 return ((link & 1)? pirq >> 4: pirq & 15); 620 } 621 622 static void 623 cyrixset(Pcidev *router, uchar link, uchar irq) 624 { 625 uchar pirq; 626 627 pirq = pcicfgr8(router, 0x5c + (link>>1)); 628 pirq &= (link & 1)? 0x0f: 0xf0; 629 pirq |= (link & 1)? (irq << 4): (irq & 15); 630 pcicfgw8(router, 0x5c + (link>>1), pirq); 631 } 632 633 typedef struct Bridge Bridge; 634 struct Bridge 635 { 636 ushort vid; 637 ushort did; 638 uchar (*get)(Pcidev *, uchar); 639 void (*set)(Pcidev *, uchar, uchar); 640 }; 641 642 static Bridge southbridges[] = { 643 { 0x8086, 0x122e, pIIxget, pIIxset }, /* Intel 82371FB */ 644 { 0x8086, 0x1234, pIIxget, pIIxset }, /* Intel 82371MX */ 645 { 0x8086, 0x7000, pIIxget, pIIxset }, /* Intel 82371SB */ 646 { 0x8086, 0x7110, pIIxget, pIIxset }, /* Intel 82371AB */ 647 { 0x8086, 0x7198, pIIxget, pIIxset }, /* Intel 82443MX (fn 1) */ 648 { 0x8086, 0x2410, pIIxget, pIIxset }, /* Intel 82801AA */ 649 { 0x8086, 0x2420, pIIxget, pIIxset }, /* Intel 82801AB */ 650 { 0x8086, 0x2440, pIIxget, pIIxset }, /* Intel 82801BA */ 651 { 0x8086, 0x2448, pIIxget, pIIxset }, /* Intel 82801BAM/CAM/DBM */ 652 { 0x8086, 0x244c, pIIxget, pIIxset }, /* Intel 82801BAM */ 653 { 0x8086, 0x244e, pIIxget, pIIxset }, /* Intel 82801 */ 654 { 0x8086, 0x2480, pIIxget, pIIxset }, /* Intel 82801CA */ 655 { 0x8086, 0x248c, pIIxget, pIIxset }, /* Intel 82801CAM */ 656 { 0x8086, 0x24c0, pIIxget, pIIxset }, /* Intel 82801DBL */ 657 { 0x8086, 0x24cc, pIIxget, pIIxset }, /* Intel 82801DBM */ 658 { 0x8086, 0x24d0, pIIxget, pIIxset }, /* Intel 82801EB */ 659 { 0x8086, 0x25a1, pIIxget, pIIxset }, /* Intel 6300ESB */ 660 { 0x8086, 0x2640, pIIxget, pIIxset }, /* Intel 82801FB */ 661 { 0x8086, 0x2641, pIIxget, pIIxset }, /* Intel 82801FBM */ 662 { 0x8086, 0x27b8, pIIxget, pIIxset }, /* Intel 82801GB */ 663 { 0x8086, 0x27b9, pIIxget, pIIxset }, /* Intel 82801GBM */ 664 { 0x8086, 0x27bd, pIIxget, pIIxset }, /* Intel 82801GB/GR */ 665 { 0x8086, 0x3a16, pIIxget, pIIxset }, /* Intel 82801JIR */ 666 { 0x8086, 0x3a40, pIIxget, pIIxset }, /* Intel 82801JI */ 667 { 0x8086, 0x3a42, pIIxget, pIIxset }, /* Intel 82801JI */ 668 { 0x8086, 0x3a48, pIIxget, pIIxset }, /* Intel 82801JI */ 669 { 0x8086, 0x2916, pIIxget, pIIxset }, /* Intel 82801? */ 670 { 0x1106, 0x0586, viaget, viaset }, /* Viatech 82C586 */ 671 { 0x1106, 0x0596, viaget, viaset }, /* Viatech 82C596 */ 672 { 0x1106, 0x0686, viaget, viaset }, /* Viatech 82C686 */ 673 { 0x1106, 0x3227, viaget, viaset }, /* Viatech VT8237 */ 674 { 0x1045, 0xc700, optiget, optiset }, /* Opti 82C700 */ 675 { 0x10b9, 0x1533, aliget, aliset }, /* Al M1533 */ 676 { 0x1039, 0x0008, pIIxget, pIIxset }, /* SI 503 */ 677 { 0x1039, 0x0496, pIIxget, pIIxset }, /* SI 496 */ 678 { 0x1078, 0x0100, cyrixget, cyrixset }, /* Cyrix 5530 Legacy */ 679 680 { 0x1022, 0x746B, nil, nil }, /* AMD 8111 */ 681 { 0x10DE, 0x00D1, nil, nil }, /* NVIDIA nForce 3 */ 682 { 0x10DE, 0x00E0, nil, nil }, /* NVIDIA nForce 3 250 Series */ 683 { 0x10DE, 0x00E1, nil, nil }, /* NVIDIA nForce 3 250 Series */ 684 { 0x1166, 0x0200, nil, nil }, /* ServerWorks ServerSet III LE */ 685 { 0x1002, 0x4377, nil, nil }, /* ATI Radeon Xpress 200M */ 686 { 0x1002, 0x4372, nil, nil }, /* ATI SB400 */ 687 }; 688 689 typedef struct Slot Slot; 690 struct Slot { 691 uchar bus; /* Pci bus number */ 692 uchar dev; /* Pci device number */ 693 uchar maps[12]; /* Avoid structs! Link and mask. */ 694 uchar slot; /* Add-in/built-in slot */ 695 uchar reserved; 696 }; 697 698 typedef struct Router Router; 699 struct Router { 700 uchar signature[4]; /* Routing table signature */ 701 uchar version[2]; /* Version number */ 702 uchar size[2]; /* Total table size */ 703 uchar bus; /* Interrupt router bus number */ 704 uchar devfn; /* Router's devfunc */ 705 uchar pciirqs[2]; /* Exclusive PCI irqs */ 706 uchar compat[4]; /* Compatible PCI interrupt router */ 707 uchar miniport[4]; /* Miniport data */ 708 uchar reserved[11]; 709 uchar checksum; 710 }; 711 712 static ushort pciirqs; /* Exclusive PCI irqs */ 713 static Bridge *southbridge; /* Which southbridge to use. */ 714 715 static void 716 pcirouting(void) 717 { 718 Slot *e; 719 Router *r; 720 int size, i, fn, tbdf; 721 Pcidev *sbpci, *pci; 722 uchar *p, pin, irq, link, *map; 723 724 /* Search for PCI interrupt routing table in BIOS */ 725 for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16) 726 if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R') 727 break; 728 729 if(p >= (uchar *)KADDR(0xfffff)) { 730 // print("no PCI intr routing table found\n"); 731 return; 732 } 733 734 r = (Router *)p; 735 736 if (0) 737 print("PCI interrupt routing table version %d.%d at %#.6luX\n", 738 r->version[0], r->version[1], (ulong)r & 0xfffff); 739 740 tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8); 741 sbpci = pcimatchtbdf(tbdf); 742 if(sbpci == nil) { 743 print("pcirouting: Cannot find south bridge %T\n", tbdf); 744 return; 745 } 746 747 for(i = 0; i != nelem(southbridges); i++) 748 if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did) 749 break; 750 751 if(i == nelem(southbridges)) { 752 print("pcirouting: ignoring south bridge %T %.4uX/%.4uX\n", tbdf, sbpci->vid, sbpci->did); 753 return; 754 } 755 southbridge = &southbridges[i]; 756 if(southbridge->get == nil || southbridge->set == nil) 757 return; 758 759 pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0]; 760 761 size = (r->size[1] << 8)|r->size[0]; 762 for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) { 763 if (0) { 764 print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot); 765 for (i = 0; i != 4; i++) { 766 uchar *m = &e->maps[i * 3]; 767 print("[%d] %.2uX %.4uX ", 768 i, m[0], (m[2] << 8)|m[1]); 769 } 770 print("\n"); 771 } 772 for(fn = 0; fn != 8; fn++) { 773 tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8); 774 pci = pcimatchtbdf(tbdf); 775 if(pci == nil) 776 continue; 777 pin = pcicfgr8(pci, PciINTP); 778 if(pin == 0 || pin == 0xff) 779 continue; 780 781 map = &e->maps[(pin - 1) * 3]; 782 link = map[0]; 783 irq = southbridge->get(sbpci, link); 784 if(irq == 0 || irq == pci->intl) 785 continue; 786 if(pci->intl != 0 && pci->intl != 0xFF) { 787 print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n", 788 tbdf, pin, link, irq, pci->intl); 789 southbridge->set(sbpci, link, pci->intl); 790 continue; 791 } 792 print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq); 793 pcicfgw8(pci, PciINTL, irq); 794 pci->intl = irq; 795 } 796 } 797 } 798 799 static void pcireservemem(void); 800 801 static int 802 pcicfgrw8bios(int tbdf, int rno, int data, int read) 803 { 804 BIOS32ci ci; 805 806 if(pcibiossi == nil) 807 return -1; 808 809 memset(&ci, 0, sizeof(BIOS32ci)); 810 ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf); 811 ci.edi = rno; 812 if(read){ 813 ci.eax = 0xB108; 814 if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 815 return ci.ecx & 0xFF; 816 } 817 else{ 818 ci.eax = 0xB10B; 819 ci.ecx = data & 0xFF; 820 if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 821 return 0; 822 } 823 824 return -1; 825 } 826 827 static int 828 pcicfgrw16bios(int tbdf, int rno, int data, int read) 829 { 830 BIOS32ci ci; 831 832 if(pcibiossi == nil) 833 return -1; 834 835 memset(&ci, 0, sizeof(BIOS32ci)); 836 ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf); 837 ci.edi = rno; 838 if(read){ 839 ci.eax = 0xB109; 840 if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 841 return ci.ecx & 0xFFFF; 842 } 843 else{ 844 ci.eax = 0xB10C; 845 ci.ecx = data & 0xFFFF; 846 if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 847 return 0; 848 } 849 850 return -1; 851 } 852 853 static int 854 pcicfgrw32bios(int tbdf, int rno, int data, int read) 855 { 856 BIOS32ci ci; 857 858 if(pcibiossi == nil) 859 return -1; 860 861 memset(&ci, 0, sizeof(BIOS32ci)); 862 ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf); 863 ci.edi = rno; 864 if(read){ 865 ci.eax = 0xB10A; 866 if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 867 return ci.ecx; 868 } 869 else{ 870 ci.eax = 0xB10D; 871 ci.ecx = data; 872 if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 873 return 0; 874 } 875 876 return -1; 877 } 878 879 static BIOS32si* 880 pcibiosinit(void) 881 { 882 BIOS32ci ci; 883 BIOS32si *si; 884 885 if((si = bios32open("$PCI")) == nil) 886 return nil; 887 888 memset(&ci, 0, sizeof(BIOS32ci)); 889 ci.eax = 0xB101; 890 if(bios32ci(si, &ci) || ci.edx != ((' '<<24)|('I'<<16)|('C'<<8)|'P')){ 891 free(si); 892 return nil; 893 } 894 if(ci.eax & 0x01) 895 pcimaxdno = 31; 896 else 897 pcimaxdno = 15; 898 pcimaxbno = ci.ecx & 0xff; 899 900 return si; 901 } 902 903 void 904 pcibussize(Pcidev *root, ulong *msize, ulong *iosize) 905 { 906 *msize = 0; 907 *iosize = 0; 908 pcibusmap(root, msize, iosize, 0); 909 } 910 911 static void 912 pcicfginit(void) 913 { 914 char *p; 915 Pcidev **list; 916 ulong mema, ioa; 917 int bno, n, pcibios; 918 919 lock(&pcicfginitlock); 920 if(pcicfgmode != -1) 921 goto out; 922 923 pcibios = 0; 924 if(getconf("*nobios")) 925 nobios = 1; 926 else if(getconf("*pcibios")) 927 pcibios = 1; 928 if(getconf("*nopcirouting")) 929 nopcirouting = 1; 930 931 /* 932 * Try to determine which PCI configuration mode is implemented. 933 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses 934 * a DWORD at 0xCF8 and another at 0xCFC and will pass through 935 * any non-DWORD accesses as normal I/O cycles. There shouldn't be 936 * a device behind these addresses so if Mode1 accesses fail try 937 * for Mode2 (Mode2 is deprecated). 938 */ 939 if(!pcibios){ 940 /* 941 * Bits [30:24] of PciADDR must be 0, 942 * according to the spec. 943 */ 944 n = inl(PciADDR); 945 if(!(n & 0x7F000000)){ 946 outl(PciADDR, 0x80000000); 947 outb(PciADDR+3, 0); 948 if(inl(PciADDR) & 0x80000000){ 949 pcicfgmode = 1; 950 pcimaxdno = 31; 951 } 952 } 953 outl(PciADDR, n); 954 955 if(pcicfgmode < 0){ 956 /* 957 * The 'key' part of PciCSE should be 0. 958 */ 959 n = inb(PciCSE); 960 if(!(n & 0xF0)){ 961 outb(PciCSE, 0x0E); 962 if(inb(PciCSE) == 0x0E){ 963 pcicfgmode = 2; 964 pcimaxdno = 15; 965 } 966 } 967 outb(PciCSE, n); 968 } 969 } 970 971 if(pcicfgmode < 0 || pcibios) { 972 if((pcibiossi = pcibiosinit()) == nil) 973 goto out; 974 pcicfgrw8 = pcicfgrw8bios; 975 pcicfgrw16 = pcicfgrw16bios; 976 pcicfgrw32 = pcicfgrw32bios; 977 pcicfgmode = 3; 978 } 979 980 fmtinstall('T', tbdffmt); 981 982 if(p = getconf("*pcimaxbno")){ 983 n = strtoul(p, 0, 0); 984 if(n < pcimaxbno) 985 pcimaxbno = n; 986 } 987 if(p = getconf("*pcimaxdno")){ 988 n = strtoul(p, 0, 0); 989 if(n < pcimaxdno) 990 pcimaxdno = n; 991 } 992 993 list = &pciroot; 994 for(bno = 0; bno <= pcimaxbno; bno++) { 995 int sbno = bno; 996 bno = pcilscan(bno, list); 997 998 while(*list) 999 list = &(*list)->link; 1000 1001 if (sbno == 0) { 1002 Pcidev *pci; 1003 1004 /* 1005 * If we have found a PCI-to-Cardbus bridge, make sure 1006 * it has no valid mappings anymore. 1007 */ 1008 for(pci = pciroot; pci != nil; pci = pci->link){ 1009 if (pci->ccrb == 6 && pci->ccru == 7) { 1010 ushort bcr; 1011 1012 /* reset the cardbus */ 1013 bcr = pcicfgr16(pci, PciBCR); 1014 pcicfgw16(pci, PciBCR, 0x40 | bcr); 1015 delay(50); 1016 } 1017 } 1018 } 1019 } 1020 1021 if(pciroot == nil) 1022 goto out; 1023 1024 if(nobios) { 1025 /* 1026 * Work out how big the top bus is 1027 */ 1028 pcibussize(pciroot, &mema, &ioa); 1029 1030 /* 1031 * Align the windows and map it 1032 */ 1033 ioa = 0x1000; 1034 mema = 0x90000000; 1035 1036 pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa); 1037 1038 pcibusmap(pciroot, &mema, &ioa, 1); 1039 DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa); 1040 1041 unlock(&pcicfginitlock); 1042 return; 1043 } 1044 1045 if (!nopcirouting) 1046 pcirouting(); 1047 1048 out: 1049 pcireservemem(); 1050 unlock(&pcicfginitlock); 1051 1052 if(getconf("*pcihinv")) 1053 pcihinv(nil); 1054 } 1055 1056 static void 1057 pcireservemem(void) 1058 { 1059 int i; 1060 Pcidev *p; 1061 1062 /* 1063 * mark all the physical address space claimed by pci devices 1064 * as in use, so that upaalloc doesn't give it out. 1065 */ 1066 for(p=pciroot; p; p=p->list) 1067 for(i=0; i<nelem(p->mem); i++) 1068 if(p->mem[i].bar && (p->mem[i].bar&1) == 0) 1069 upareserve(p->mem[i].bar&~0x0F, p->mem[i].size); 1070 } 1071 1072 static int 1073 pcicfgrw8raw(int tbdf, int rno, int data, int read) 1074 { 1075 int o, type, x; 1076 1077 if(pcicfgmode == -1) 1078 pcicfginit(); 1079 1080 if(BUSBNO(tbdf)) 1081 type = 0x01; 1082 else 1083 type = 0x00; 1084 x = -1; 1085 if(BUSDNO(tbdf) > pcimaxdno) 1086 return x; 1087 1088 lock(&pcicfglock); 1089 switch(pcicfgmode){ 1090 1091 case 1: 1092 o = rno & 0x03; 1093 rno &= ~0x03; 1094 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 1095 if(read) 1096 x = inb(PciDATA+o); 1097 else 1098 outb(PciDATA+o, data); 1099 outl(PciADDR, 0); 1100 break; 1101 1102 case 2: 1103 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 1104 outb(PciFORWARD, BUSBNO(tbdf)); 1105 if(read) 1106 x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno); 1107 else 1108 outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 1109 outb(PciCSE, 0); 1110 break; 1111 } 1112 unlock(&pcicfglock); 1113 1114 return x; 1115 } 1116 1117 int 1118 pcicfgr8(Pcidev* pcidev, int rno) 1119 { 1120 return pcicfgrw8(pcidev->tbdf, rno, 0, 1); 1121 } 1122 1123 void 1124 pcicfgw8(Pcidev* pcidev, int rno, int data) 1125 { 1126 pcicfgrw8(pcidev->tbdf, rno, data, 0); 1127 } 1128 1129 static int 1130 pcicfgrw16raw(int tbdf, int rno, int data, int read) 1131 { 1132 int o, type, x; 1133 1134 if(pcicfgmode == -1) 1135 pcicfginit(); 1136 1137 if(BUSBNO(tbdf)) 1138 type = 0x01; 1139 else 1140 type = 0x00; 1141 x = -1; 1142 if(BUSDNO(tbdf) > pcimaxdno) 1143 return x; 1144 1145 lock(&pcicfglock); 1146 switch(pcicfgmode){ 1147 1148 case 1: 1149 o = rno & 0x02; 1150 rno &= ~0x03; 1151 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 1152 if(read) 1153 x = ins(PciDATA+o); 1154 else 1155 outs(PciDATA+o, data); 1156 outl(PciADDR, 0); 1157 break; 1158 1159 case 2: 1160 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 1161 outb(PciFORWARD, BUSBNO(tbdf)); 1162 if(read) 1163 x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno); 1164 else 1165 outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 1166 outb(PciCSE, 0); 1167 break; 1168 } 1169 unlock(&pcicfglock); 1170 1171 return x; 1172 } 1173 1174 int 1175 pcicfgr16(Pcidev* pcidev, int rno) 1176 { 1177 return pcicfgrw16(pcidev->tbdf, rno, 0, 1); 1178 } 1179 1180 void 1181 pcicfgw16(Pcidev* pcidev, int rno, int data) 1182 { 1183 pcicfgrw16(pcidev->tbdf, rno, data, 0); 1184 } 1185 1186 static int 1187 pcicfgrw32raw(int tbdf, int rno, int data, int read) 1188 { 1189 int type, x; 1190 1191 if(pcicfgmode == -1) 1192 pcicfginit(); 1193 1194 if(BUSBNO(tbdf)) 1195 type = 0x01; 1196 else 1197 type = 0x00; 1198 x = -1; 1199 if(BUSDNO(tbdf) > pcimaxdno) 1200 return x; 1201 1202 lock(&pcicfglock); 1203 switch(pcicfgmode){ 1204 1205 case 1: 1206 rno &= ~0x03; 1207 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 1208 if(read) 1209 x = inl(PciDATA); 1210 else 1211 outl(PciDATA, data); 1212 outl(PciADDR, 0); 1213 break; 1214 1215 case 2: 1216 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 1217 outb(PciFORWARD, BUSBNO(tbdf)); 1218 if(read) 1219 x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno); 1220 else 1221 outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 1222 outb(PciCSE, 0); 1223 break; 1224 } 1225 unlock(&pcicfglock); 1226 1227 return x; 1228 } 1229 1230 int 1231 pcicfgr32(Pcidev* pcidev, int rno) 1232 { 1233 return pcicfgrw32(pcidev->tbdf, rno, 0, 1); 1234 } 1235 1236 void 1237 pcicfgw32(Pcidev* pcidev, int rno, int data) 1238 { 1239 pcicfgrw32(pcidev->tbdf, rno, data, 0); 1240 } 1241 1242 Pcidev* 1243 pcimatch(Pcidev* prev, int vid, int did) 1244 { 1245 if(pcicfgmode == -1) 1246 pcicfginit(); 1247 1248 if(prev == nil) 1249 prev = pcilist; 1250 else 1251 prev = prev->list; 1252 1253 while(prev != nil){ 1254 if((vid == 0 || prev->vid == vid) 1255 && (did == 0 || prev->did == did)) 1256 break; 1257 prev = prev->list; 1258 } 1259 return prev; 1260 } 1261 1262 Pcidev* 1263 pcimatchtbdf(int tbdf) 1264 { 1265 Pcidev *pcidev; 1266 1267 if(pcicfgmode == -1) 1268 pcicfginit(); 1269 1270 for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) { 1271 if(pcidev->tbdf == tbdf) 1272 break; 1273 } 1274 return pcidev; 1275 } 1276 1277 uchar 1278 pciipin(Pcidev *pci, uchar pin) 1279 { 1280 if (pci == nil) 1281 pci = pcilist; 1282 1283 while (pci) { 1284 uchar intl; 1285 1286 if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff) 1287 return pci->intl; 1288 1289 if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0) 1290 return intl; 1291 1292 pci = pci->list; 1293 } 1294 return 0; 1295 } 1296 1297 static void 1298 pcilhinv(Pcidev* p) 1299 { 1300 int i; 1301 Pcidev *t; 1302 1303 if(p == nil) { 1304 putstrn(PCICONS.output, PCICONS.ptr); 1305 p = pciroot; 1306 print("bus dev type vid did intl memory\n"); 1307 } 1308 for(t = p; t != nil; t = t->link) { 1309 print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d ", 1310 BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf), 1311 t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl); 1312 1313 for(i = 0; i < nelem(p->mem); i++) { 1314 if(t->mem[i].size == 0) 1315 continue; 1316 print("%d:%.8lux %d ", i, 1317 t->mem[i].bar, t->mem[i].size); 1318 } 1319 if(t->ioa.bar || t->ioa.size) 1320 print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size); 1321 if(t->mema.bar || t->mema.size) 1322 print("mema:%.8lux %d ", t->mema.bar, t->mema.size); 1323 if(t->bridge) 1324 print("->%d", BUSBNO(t->bridge->tbdf)); 1325 print("\n"); 1326 } 1327 while(p != nil) { 1328 if(p->bridge != nil) 1329 pcilhinv(p->bridge); 1330 p = p->link; 1331 } 1332 } 1333 1334 void 1335 pcihinv(Pcidev* p) 1336 { 1337 if(pcicfgmode == -1) 1338 pcicfginit(); 1339 lock(&pcicfginitlock); 1340 pcilhinv(p); 1341 unlock(&pcicfginitlock); 1342 } 1343 1344 void 1345 pcireset(void) 1346 { 1347 Pcidev *p; 1348 1349 if(pcicfgmode == -1) 1350 pcicfginit(); 1351 1352 for(p = pcilist; p != nil; p = p->list) { 1353 /* don't mess with the bridges */ 1354 if(p->ccrb == 0x06) 1355 continue; 1356 pciclrbme(p); 1357 } 1358 } 1359 1360 void 1361 pcisetioe(Pcidev* p) 1362 { 1363 p->pcr |= IOen; 1364 pcicfgw16(p, PciPCR, p->pcr); 1365 } 1366 1367 void 1368 pciclrioe(Pcidev* p) 1369 { 1370 p->pcr &= ~IOen; 1371 pcicfgw16(p, PciPCR, p->pcr); 1372 } 1373 1374 void 1375 pcisetbme(Pcidev* p) 1376 { 1377 p->pcr |= MASen; 1378 pcicfgw16(p, PciPCR, p->pcr); 1379 } 1380 1381 void 1382 pciclrbme(Pcidev* p) 1383 { 1384 p->pcr &= ~MASen; 1385 pcicfgw16(p, PciPCR, p->pcr); 1386 } 1387 1388 void 1389 pcisetmwi(Pcidev* p) 1390 { 1391 p->pcr |= MemWrInv; 1392 pcicfgw16(p, PciPCR, p->pcr); 1393 } 1394 1395 void 1396 pciclrmwi(Pcidev* p) 1397 { 1398 p->pcr &= ~MemWrInv; 1399 pcicfgw16(p, PciPCR, p->pcr); 1400 } 1401 1402 static int 1403 pcigetpmrb(Pcidev* p) 1404 { 1405 int ptr; 1406 1407 if(p->pmrb != 0) 1408 return p->pmrb; 1409 p->pmrb = -1; 1410 1411 /* 1412 * If there are no extended capabilities implemented, 1413 * (bit 4 in the status register) assume there's no standard 1414 * power management method. 1415 * Find the capabilities pointer based on PCI header type. 1416 */ 1417 if(!(pcicfgr16(p, PciPSR) & 0x0010)) 1418 return -1; 1419 switch(pcicfgr8(p, PciHDT)){ 1420 default: 1421 return -1; 1422 case 0: /* all other */ 1423 case 1: /* PCI to PCI bridge */ 1424 ptr = 0x34; 1425 break; 1426 case 2: /* CardBus bridge */ 1427 ptr = 0x14; 1428 break; 1429 } 1430 ptr = pcicfgr32(p, ptr); 1431 1432 while(ptr != 0){ 1433 /* 1434 * Check for validity. 1435 * Can't be in standard header and must be double 1436 * word aligned. 1437 */ 1438 if(ptr < 0x40 || (ptr & ~0xFC)) 1439 return -1; 1440 if(pcicfgr8(p, ptr) == 0x01){ 1441 p->pmrb = ptr; 1442 return ptr; 1443 } 1444 1445 ptr = pcicfgr8(p, ptr+1); 1446 } 1447 1448 return -1; 1449 } 1450 1451 int 1452 pcigetpms(Pcidev* p) 1453 { 1454 int pmcsr, ptr; 1455 1456 if((ptr = pcigetpmrb(p)) == -1) 1457 return -1; 1458 1459 /* 1460 * Power Management Register Block: 1461 * offset 0: Capability ID 1462 * 1: next item pointer 1463 * 2: capabilities 1464 * 4: control/status 1465 * 6: bridge support extensions 1466 * 7: data 1467 */ 1468 pmcsr = pcicfgr16(p, ptr+4); 1469 1470 return pmcsr & 0x0003; 1471 } 1472 1473 int 1474 pcisetpms(Pcidev* p, int state) 1475 { 1476 int ostate, pmc, pmcsr, ptr; 1477 1478 if((ptr = pcigetpmrb(p)) == -1) 1479 return -1; 1480 1481 pmc = pcicfgr16(p, ptr+2); 1482 pmcsr = pcicfgr16(p, ptr+4); 1483 ostate = pmcsr & 0x0003; 1484 pmcsr &= ~0x0003; 1485 1486 switch(state){ 1487 default: 1488 return -1; 1489 case 0: 1490 break; 1491 case 1: 1492 if(!(pmc & 0x0200)) 1493 return -1; 1494 break; 1495 case 2: 1496 if(!(pmc & 0x0400)) 1497 return -1; 1498 break; 1499 case 3: 1500 break; 1501 } 1502 pmcsr |= state; 1503 pcicfgw16(p, ptr+4, pmcsr); 1504 1505 return ostate; 1506 } 1507