pci_cfgreg.c revision 89577
1/* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4 * Copyright (c) 2000, BSDi 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD: head/sys/amd64/pci/pci_cfgreg.c 89577 2002-01-20 03:28:29Z imp $ 29 * 30 */ 31 32#include <sys/param.h> /* XXX trim includes */ 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/kernel.h> 36#include <sys/module.h> 37#include <sys/malloc.h> 38#include <vm/vm.h> 39#include <vm/pmap.h> 40#include <machine/md_var.h> 41#include <pci/pcivar.h> 42#include <pci/pcireg.h> 43#include <isa/isavar.h> 44#include <machine/nexusvar.h> 45#include <machine/pci_cfgreg.h> 46#include <machine/segments.h> 47#include <machine/pc/bios.h> 48 49#ifdef APIC_IO 50#include <machine/smp.h> 51#endif /* APIC_IO */ 52 53#include "pcib_if.h" 54 55#define PRVERB(a) printf a 56 57static int cfgmech; 58static int devmax; 59static int usebios; 60static int enable_pcibios = 0; 61 62TUNABLE_INT("hw.pci.enable_pcibios", &enable_pcibios); 63 64static int pci_cfgintr_unique(struct PIR_entry *pe, int pin); 65static int pci_cfgintr_linked(struct PIR_entry *pe, int pin); 66static int pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin); 67static int pci_cfgintr_virgin(struct PIR_entry *pe, int pin); 68 69static int pcibios_cfgread(int bus, int slot, int func, int reg, int bytes); 70static void pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); 71static int pcibios_cfgopen(void); 72static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); 73static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); 74static int pcireg_cfgopen(void); 75 76static struct PIR_table *pci_route_table; 77static int pci_route_count; 78 79int 80pci_pcibios_active(void) 81{ 82 return usebios; 83} 84 85int 86pci_kill_pcibios(void) 87{ 88 usebios = 0; 89 return pcireg_cfgopen() != 0; 90} 91 92static u_int16_t 93pcibios_get_version(void) 94{ 95 struct bios_regs args; 96 97 if (PCIbios.entry == 0) { 98 PRVERB(("pcibios: No call entry point\n")); 99 return (0); 100 } 101 args.eax = PCIBIOS_BIOS_PRESENT; 102 if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { 103 PRVERB(("pcibios: BIOS_PRESENT call failed\n")); 104 return (0); 105 } 106 if (args.edx != 0x20494350) { 107 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n")); 108 return (0); 109 } 110 return (args.ebx & 0xffff); 111} 112 113/* 114 * Initialise access to PCI configuration space 115 */ 116int 117pci_cfgregopen(void) 118{ 119 static int opened = 0; 120 u_long sigaddr; 121 static struct PIR_table *pt; 122 u_int8_t ck, *cv; 123 int i; 124 125 if (opened) 126 return(1); 127 128 if (pcibios_cfgopen() != 0) { 129 usebios = 1; 130 } else if (pcireg_cfgopen() != 0) { 131 usebios = 0; 132 } else { 133 return(0); 134 } 135 136 /* 137 * Look for the interrupt routing table. 138 * 139 * We use PCI BIOS's PIR table if it's available $PIR is the 140 * standard way to do this. Sadly, some machines are not 141 * standards conforming and have _PIR instead. We shrug and cope 142 * by looking for both. 143 */ 144 if (pcibios_get_version() >= 0x0210 && pt == NULL) { 145 sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0); 146 if (sigaddr == 0) 147 sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0); 148 if (sigaddr != 0) { 149 pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); 150 for (cv = (u_int8_t *)pt, ck = 0, i = 0; 151 i < (pt->pt_header.ph_length); i++) { 152 ck += cv[i]; 153 } 154 if (ck == 0) { 155 pci_route_table = pt; 156 pci_route_count = (pt->pt_header.ph_length - 157 sizeof(struct PIR_header)) / sizeof(struct PIR_entry); 158 printf("Using $PIR table, %d entries at %p\n", 159 pci_route_count, pci_route_table); 160 } 161 } 162 } 163 opened = 1; 164 return(1); 165} 166 167/* 168 * Read configuration space register 169 */ 170static u_int32_t 171pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes) 172{ 173 return(usebios ? 174 pcibios_cfgread(bus, slot, func, reg, bytes) : 175 pcireg_cfgread(bus, slot, func, reg, bytes)); 176} 177 178u_int32_t 179pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 180{ 181#ifdef APIC_IO 182 /* 183 * If we are using the APIC, the contents of the intline register will probably 184 * be wrong (since they are set up for use with the PIC. 185 * Rather than rewrite these registers (maybe that would be smarter) we trap 186 * attempts to read them and translate to our private vector numbers. 187 */ 188 if ((reg == PCIR_INTLINE) && (bytes == 1)) { 189 int pin, line; 190 191 pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); 192 line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); 193 194 if (pin != 0) { 195 int airq; 196 197 airq = pci_apic_irq(bus, slot, pin); 198 if (airq >= 0) { 199 /* PCI specific entry found in MP table */ 200 if (airq != line) 201 undirect_pci_irq(line); 202 return(airq); 203 } else { 204 /* 205 * PCI interrupts might be redirected to the 206 * ISA bus according to some MP tables. Use the 207 * same methods as used by the ISA devices 208 * devices to find the proper IOAPIC int pin. 209 */ 210 airq = isa_apic_irq(line); 211 if ((airq >= 0) && (airq != line)) { 212 /* XXX: undirect_pci_irq() ? */ 213 undirect_isa_irq(line); 214 return(airq); 215 } 216 } 217 } 218 return(line); 219 } 220#endif /* APIC_IO */ 221 return(pci_do_cfgregread(bus, slot, func, reg, bytes)); 222} 223 224/* 225 * Write configuration space register 226 */ 227void 228pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 229{ 230 return(usebios ? 231 pcibios_cfgwrite(bus, slot, func, reg, data, bytes) : 232 pcireg_cfgwrite(bus, slot, func, reg, data, bytes)); 233} 234 235/* 236 * Route a PCI interrupt 237 * 238 * XXX we don't do anything "right" with the function number in the PIR table 239 * (because the consumer isn't currently passing it in). We don't care 240 * anyway, due to the way PCI interrupts are assigned. 241 */ 242int 243pci_cfgintr(int bus, int device, int pin) 244{ 245 struct PIR_entry *pe; 246 int i, irq; 247 struct bios_regs args; 248 u_int16_t v; 249 int already = 0; 250 251 v = pcibios_get_version(); 252 if (v < 0x0210) { 253 PRVERB(( 254 "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n", 255 (v & 0xff00) >> 8, v & 0xff)); 256 return (255); 257 } 258 if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || 259 (pin < 1) || (pin > 4)) 260 return(255); 261 262 /* 263 * Scan the entry table for a contender 264 */ 265 for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, pe++) { 266 if ((bus != pe->pe_bus) || (device != pe->pe_device)) 267 continue; 268 269 irq = pci_cfgintr_linked(pe, pin); 270 if (irq != 255) 271 already = 1; 272 if (irq == 255) 273 irq = pci_cfgintr_unique(pe, pin); 274 if (irq == 255) 275 irq = pci_cfgintr_virgin(pe, pin); 276 if (irq == 255) 277 break; 278 279 /* 280 * Ask the BIOS to route the interrupt 281 */ 282 args.eax = PCIBIOS_ROUTE_INTERRUPT; 283 args.ebx = (bus << 8) | (device << 3); 284 args.ecx = (irq << 8) | (0xa + pin - 1); /* pin value is 0xa - 0xd */ 285 if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) && !already) { 286 /* 287 * XXX if it fails, we should try to smack the router 288 * hardware directly. 289 * XXX Also, there may be other choices that we can try that 290 * will work. 291 */ 292 PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n")); 293 return(255); 294 } 295 printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus, device, 'A' + pin - 1, irq); 296 return(irq); 297 } 298 299 PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus, device, 'A' + pin - 1)); 300 return(255); 301} 302 303/* 304 * Look to see if the routing table claims this pin is uniquely routed. 305 */ 306static int 307pci_cfgintr_unique(struct PIR_entry *pe, int pin) 308{ 309 int irq; 310 311 if (powerof2(pe->pe_intpin[pin - 1].irqs)) { 312 irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1; 313 PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq)); 314 return(irq); 315 } 316 return(255); 317} 318 319/* 320 * Look for another device which shares the same link byte and 321 * already has a unique IRQ, or which has had one routed already. 322 */ 323static int 324pci_cfgintr_linked(struct PIR_entry *pe, int pin) 325{ 326 struct PIR_entry *oe; 327 struct PIR_intpin *pi; 328 int i, j, irq; 329 330 /* 331 * Scan table slots. 332 */ 333 for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, oe++) { 334 335 /* scan interrupt pins */ 336 for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) { 337 338 /* don't look at the entry we're trying to match with */ 339 if ((pe == oe) && (i == (pin - 1))) 340 continue; 341 342 /* compare link bytes */ 343 if (pi->link != pe->pe_intpin[pin - 1].link) 344 continue; 345 346 /* link destination mapped to a unique interrupt? */ 347 if (powerof2(pi->irqs)) { 348 irq = ffs(pi->irqs) - 1; 349 PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", 350 pi->link, irq)); 351 return(irq); 352 } 353 354 /* look for the real PCI device that matches this table entry */ 355 if ((irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, j, pin)) != 255) 356 return(irq); 357 } 358 } 359 return(255); 360} 361 362/* 363 * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and 364 * see if it has already been assigned an interrupt. 365 */ 366static int 367pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin) 368{ 369 devclass_t pci_devclass; 370 device_t *pci_devices; 371 int pci_count; 372 device_t *pci_children; 373 int pci_childcount; 374 device_t *busp, *childp; 375 int i, j, irq; 376 377 /* 378 * Find all the PCI busses. 379 */ 380 pci_count = 0; 381 if ((pci_devclass = devclass_find("pci")) != NULL) 382 devclass_get_devices(pci_devclass, &pci_devices, &pci_count); 383 384 /* 385 * Scan all the PCI busses/devices looking for this one. 386 */ 387 irq = 255; 388 for (i = 0, busp = pci_devices; (i < pci_count) && (irq == 255); i++, busp++) { 389 pci_childcount = 0; 390 device_get_children(*busp, &pci_children, &pci_childcount); 391 392 for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) { 393 if ((pci_get_bus(*childp) == bus) && 394 (pci_get_slot(*childp) == device) && 395 (pci_get_intpin(*childp) == matchpin)) { 396 irq = pci_get_irq(*childp); 397 /* 398 * Some BIOS writers seem to want to ignore the spec and put 399 * 0 in the intline rather than 255 to indicate none. Once 400 * we've found one that matches, we break because there can 401 * be no others (which is why test looks a little odd). 402 */ 403 if (irq == 0) 404 irq = 255; 405 if (irq != 255) 406 PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", 407 pe->pe_intpin[pin - 1].link, irq, 408 pci_get_bus(*childp), pci_get_slot(*childp), pci_get_function(*childp))); 409 break; 410 } 411 } 412 if (pci_children != NULL) 413 free(pci_children, M_TEMP); 414 } 415 if (pci_devices != NULL) 416 free(pci_devices, M_TEMP); 417 return(irq); 418} 419 420/* 421 * Pick a suitable IRQ from those listed as routable to this device. 422 */ 423static int 424pci_cfgintr_virgin(struct PIR_entry *pe, int pin) 425{ 426 int irq, ibit; 427 428 /* first scan the set of PCI-only interrupts and see if any of these are routable */ 429 for (irq = 0; irq < 16; irq++) { 430 ibit = (1 << irq); 431 432 /* can we use this interrupt? */ 433 if ((pci_route_table->pt_header.ph_pci_irqs & ibit) && 434 (pe->pe_intpin[pin - 1].irqs & ibit)) { 435 PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq)); 436 return(irq); 437 } 438 } 439 440 /* life is tough, so just pick an interrupt */ 441 for (irq = 0; irq < 16; irq++) { 442 ibit = (1 << irq); 443 444 if (pe->pe_intpin[pin - 1].irqs & ibit) { 445 PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq)); 446 return(irq); 447 } 448 } 449 return(255); 450} 451 452 453/* 454 * Config space access using BIOS functions 455 */ 456static int 457pcibios_cfgread(int bus, int slot, int func, int reg, int bytes) 458{ 459 struct bios_regs args; 460 u_int mask; 461 462 switch(bytes) { 463 case 1: 464 args.eax = PCIBIOS_READ_CONFIG_BYTE; 465 mask = 0xff; 466 break; 467 case 2: 468 args.eax = PCIBIOS_READ_CONFIG_WORD; 469 mask = 0xffff; 470 break; 471 case 4: 472 args.eax = PCIBIOS_READ_CONFIG_DWORD; 473 mask = 0xffffffff; 474 break; 475 default: 476 return(-1); 477 } 478 args.ebx = (bus << 8) | (slot << 3) | func; 479 args.edi = reg; 480 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 481 /* check call results? */ 482 return(args.ecx & mask); 483} 484 485static void 486pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 487{ 488 struct bios_regs args; 489 490 switch(bytes) { 491 case 1: 492 args.eax = PCIBIOS_WRITE_CONFIG_BYTE; 493 break; 494 case 2: 495 args.eax = PCIBIOS_WRITE_CONFIG_WORD; 496 break; 497 case 4: 498 args.eax = PCIBIOS_WRITE_CONFIG_DWORD; 499 break; 500 default: 501 return; 502 } 503 args.ebx = (bus << 8) | (slot << 3) | func; 504 args.ecx = data; 505 args.edi = reg; 506 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 507} 508 509/* 510 * Determine whether there is a PCI BIOS present 511 */ 512static int 513pcibios_cfgopen(void) 514{ 515 u_int16_t v = 0; 516 517 if (PCIbios.entry != 0 && enable_pcibios) { 518 v = pcibios_get_version(); 519 if (v > 0) 520 printf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8, 521 v & 0xff); 522 } 523 return (v > 0); 524} 525 526/* 527 * Configuration space access using direct register operations 528 */ 529 530/* enable configuration space accesses and return data port address */ 531static int 532pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 533{ 534 int dataport = 0; 535 536 if (bus <= PCI_BUSMAX 537 && slot < devmax 538 && func <= PCI_FUNCMAX 539 && reg <= PCI_REGMAX 540 && bytes != 3 541 && (unsigned) bytes <= 4 542 && (reg & (bytes -1)) == 0) { 543 switch (cfgmech) { 544 case 1: 545 outl(CONF1_ADDR_PORT, (1 << 31) 546 | (bus << 16) | (slot << 11) 547 | (func << 8) | (reg & ~0x03)); 548 dataport = CONF1_DATA_PORT + (reg & 0x03); 549 break; 550 case 2: 551 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 552 outb(CONF2_FORWARD_PORT, bus); 553 dataport = 0xc000 | (slot << 8) | reg; 554 break; 555 } 556 } 557 return (dataport); 558} 559 560/* disable configuration space accesses */ 561static void 562pci_cfgdisable(void) 563{ 564 switch (cfgmech) { 565 case 1: 566 outl(CONF1_ADDR_PORT, 0); 567 break; 568 case 2: 569 outb(CONF2_ENABLE_PORT, 0); 570 outb(CONF2_FORWARD_PORT, 0); 571 break; 572 } 573} 574 575static int 576pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 577{ 578 int data = -1; 579 int port; 580 581 port = pci_cfgenable(bus, slot, func, reg, bytes); 582 583 if (port != 0) { 584 switch (bytes) { 585 case 1: 586 data = inb(port); 587 break; 588 case 2: 589 data = inw(port); 590 break; 591 case 4: 592 data = inl(port); 593 break; 594 } 595 pci_cfgdisable(); 596 } 597 return (data); 598} 599 600static void 601pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 602{ 603 int port; 604 605 port = pci_cfgenable(bus, slot, func, reg, bytes); 606 if (port != 0) { 607 switch (bytes) { 608 case 1: 609 outb(port, data); 610 break; 611 case 2: 612 outw(port, data); 613 break; 614 case 4: 615 outl(port, data); 616 break; 617 } 618 pci_cfgdisable(); 619 } 620} 621 622/* check whether the configuration mechanism has been correctly identified */ 623static int 624pci_cfgcheck(int maxdev) 625{ 626 u_char device; 627 628 if (bootverbose) 629 printf("pci_cfgcheck:\tdevice "); 630 631 for (device = 0; device < maxdev; device++) { 632 unsigned id, class, header; 633 if (bootverbose) 634 printf("%d ", device); 635 636 id = inl(pci_cfgenable(0, device, 0, 0, 4)); 637 if (id == 0 || id == -1) 638 continue; 639 640 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 641 if (bootverbose) 642 printf("[class=%06x] ", class); 643 if (class == 0 || (class & 0xf870ff) != 0) 644 continue; 645 646 header = inb(pci_cfgenable(0, device, 0, 14, 1)); 647 if (bootverbose) 648 printf("[hdr=%02x] ", header); 649 if ((header & 0x7e) != 0) 650 continue; 651 652 if (bootverbose) 653 printf("is there (id=%08x)\n", id); 654 655 pci_cfgdisable(); 656 return (1); 657 } 658 if (bootverbose) 659 printf("-- nothing found\n"); 660 661 pci_cfgdisable(); 662 return (0); 663} 664 665static int 666pcireg_cfgopen(void) 667{ 668 unsigned long mode1res,oldval1; 669 unsigned char mode2res,oldval2; 670 671 oldval1 = inl(CONF1_ADDR_PORT); 672 673 if (bootverbose) { 674 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 675 oldval1); 676 } 677 678 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 679 680 cfgmech = 1; 681 devmax = 32; 682 683 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 684 outb(CONF1_ADDR_PORT +3, 0); 685 mode1res = inl(CONF1_ADDR_PORT); 686 outl(CONF1_ADDR_PORT, oldval1); 687 688 if (bootverbose) 689 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 690 mode1res, CONF1_ENABLE_CHK); 691 692 if (mode1res) { 693 if (pci_cfgcheck(32)) 694 return (cfgmech); 695 } 696 697 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 698 mode1res = inl(CONF1_ADDR_PORT); 699 outl(CONF1_ADDR_PORT, oldval1); 700 701 if (bootverbose) 702 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 703 mode1res, CONF1_ENABLE_CHK1); 704 705 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 706 if (pci_cfgcheck(32)) 707 return (cfgmech); 708 } 709 } 710 711 oldval2 = inb(CONF2_ENABLE_PORT); 712 713 if (bootverbose) { 714 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 715 oldval2); 716 } 717 718 if ((oldval2 & 0xf0) == 0) { 719 720 cfgmech = 2; 721 devmax = 16; 722 723 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 724 mode2res = inb(CONF2_ENABLE_PORT); 725 outb(CONF2_ENABLE_PORT, oldval2); 726 727 if (bootverbose) 728 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 729 mode2res, CONF2_ENABLE_CHK); 730 731 if (mode2res == CONF2_ENABLE_RES) { 732 if (bootverbose) 733 printf("pci_open(2a):\tnow trying mechanism 2\n"); 734 735 if (pci_cfgcheck(16)) 736 return (cfgmech); 737 } 738 } 739 740 cfgmech = 0; 741 devmax = 0; 742 return (cfgmech); 743} 744 745