pci_cfgreg.c revision 69783
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 69783 2000-12-08 22:11:23Z msmith $ 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 55static int cfgmech; 56static int devmax; 57static int usebios; 58 59static int pci_cfgintr_unique(struct PIR_entry *pe, int pin); 60static int pci_cfgintr_linked(struct PIR_entry *pe, int pin); 61static int pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin); 62static int pci_cfgintr_virgin(struct PIR_entry *pe, int pin); 63 64static int pcibios_cfgread(int bus, int slot, int func, int reg, int bytes); 65static void pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); 66static int pcibios_cfgopen(void); 67static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); 68static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); 69static int pcireg_cfgopen(void); 70 71static struct PIR_table *pci_route_table; 72static int pci_route_count; 73 74/* 75 * Initialise access to PCI configuration space 76 */ 77int 78pci_cfgregopen(void) 79{ 80 static int opened = 0; 81 u_long sigaddr; 82 static struct PIR_table *pt; 83 u_int8_t ck, *cv; 84 int i; 85 86 if (opened) 87 return(1); 88 89 if (pcibios_cfgopen() != 0) { 90 usebios = 1; 91 } else if (pcireg_cfgopen() != 0) { 92 usebios = 0; 93 } else { 94 return(0); 95 } 96 97 /* 98 * Look for the interrupt routing table. 99 */ 100 /* XXX use PCI BIOS if it's available */ 101 102 if ((pt == NULL) && ((sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0)) != 0)) { 103 pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); 104 for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < (pt->pt_header.ph_length); i++) { 105 ck += cv[i]; 106 } 107 if (ck == 0) { 108 pci_route_table = pt; 109 pci_route_count = (pt->pt_header.ph_length - sizeof(struct PIR_header)) / sizeof(struct PIR_entry); 110 printf("Using $PIR table, %d entries at %p\n", pci_route_count, pci_route_table); 111 } 112 } 113 114 opened = 1; 115 return(1); 116} 117 118/* 119 * Read configuration space register 120 */ 121u_int32_t 122pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes) 123{ 124 return(usebios ? 125 pcibios_cfgread(bus, slot, func, reg, bytes) : 126 pcireg_cfgread(bus, slot, func, reg, bytes)); 127} 128 129u_int32_t 130pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 131{ 132#ifdef APIC_IO 133 /* 134 * If we are using the APIC, the contents of the intline register will probably 135 * be wrong (since they are set up for use with the PIC. 136 * Rather than rewrite these registers (maybe that would be smarter) we trap 137 * attempts to read them and translate to our private vector numbers. 138 */ 139 if ((reg == PCIR_INTLINE) && (bytes == 1)) { 140 int pin, line, airq; 141 142 pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); 143 line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); 144 145 if (pin != 0) { 146 int airq; 147 148 airq = pci_apic_irq(bus, slot, pin); 149 if (airq >= 0) { 150 /* PCI specific entry found in MP table */ 151 if (airq != line) 152 undirect_pci_irq(line); 153 return(airq); 154 } else { 155 /* 156 * PCI interrupts might be redirected to the 157 * ISA bus according to some MP tables. Use the 158 * same methods as used by the ISA devices 159 * devices to find the proper IOAPIC int pin. 160 */ 161 airq = isa_apic_irq(line); 162 if ((airq >= 0) && (airq != line)) { 163 /* XXX: undirect_pci_irq() ? */ 164 undirect_isa_irq(line); 165 return(airq); 166 } 167 } 168 } 169 return(line); 170 } 171#endif /* APIC_IO */ 172 return(pci_do_cfgregread(bus, slot, func, reg, bytes)); 173} 174 175/* 176 * Write configuration space register 177 */ 178void 179pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 180{ 181 return(usebios ? 182 pcibios_cfgwrite(bus, slot, func, reg, data, bytes) : 183 pcireg_cfgwrite(bus, slot, func, reg, data, bytes)); 184} 185 186/* 187 * Route a PCI interrupt 188 * 189 * XXX we don't do anything "right" with the function number in the PIR table 190 * (because the consumer isn't currently passing it in). We don't care 191 * anyway, due to the way PCI interrupts are assigned. 192 */ 193int 194pci_cfgintr(int bus, int device, int pin) 195{ 196 struct PIR_entry *pe; 197 int i, irq; 198 struct bios_regs args; 199 200 if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || 201 (pin < 1) || (pin > 4)) 202 return(255); 203 204 /* 205 * Scan the entry table for a contender 206 */ 207 for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, pe++) { 208 if ((bus != pe->pe_bus) || (device != pe->pe_device)) 209 continue; 210 211 irq = pci_cfgintr_unique(pe, pin); 212 if (irq == 255) 213 irq = pci_cfgintr_linked(pe, pin); 214 if (irq == 255) 215 irq = pci_cfgintr_virgin(pe, pin); 216 217 if (irq == 255) 218 break; 219 220 221 /* 222 * Ask the BIOS to route the interrupt 223 */ 224 args.eax = PCIBIOS_ROUTE_INTERRUPT; 225 args.ebx = (bus << 8) | (device << 3); 226 args.ecx = (irq << 8) | (0xa + pin - 1); /* pin value is 0xa - 0xd */ 227 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 228 229 /* 230 * XXX if it fails, we should try to smack the router hardware directly 231 */ 232 233 printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", 234 bus, device, 'A' + pin - 1, irq); 235 return(irq); 236 } 237 238 printf("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus, device, 'A' + pin - 1); 239 return(255); 240} 241 242/* 243 * Look to see if the routing table claims this pin is uniquely routed. 244 */ 245static int 246pci_cfgintr_unique(struct PIR_entry *pe, int pin) 247{ 248 int irq; 249 250 if (powerof2(pe->pe_intpin[pin - 1].irqs)) { 251 irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1; 252 printf("pci_cfgintr_unique: hard-routed to irq %d\n", irq); 253 return(irq); 254 } 255 return(255); 256} 257 258/* 259 * Look for another device which shares the same link byte and 260 * already has a unique IRQ, or which has had one routed already. 261 */ 262static int 263pci_cfgintr_linked(struct PIR_entry *pe, int pin) 264{ 265 struct PIR_entry *oe; 266 struct PIR_intpin *pi; 267 int i, j, irq; 268 269 /* 270 * Scan table slots. 271 */ 272 for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, oe++) { 273 274 /* scan interrupt pins */ 275 for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) { 276 277 /* don't look at the entry we're trying to match with */ 278 if ((pe == oe) && (i == (pin - 1))) 279 continue; 280 281 /* compare link bytes */ 282 if (pi->link != pe->pe_intpin[pin - 1].link) 283 continue; 284 285 /* link destination mapped to a unique interrupt? */ 286 if (powerof2(pi->irqs)) { 287 irq = ffs(pi->irqs) - 1; 288 printf("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", 289 pi->link, irq); 290 return(irq); 291 } 292 293 /* look for the real PCI device that matches this table entry */ 294 if ((irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, j, pin)) != 255) 295 return(irq); 296 } 297 } 298 return(255); 299} 300 301/* 302 * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and 303 * see if it has already been assigned an interrupt. 304 */ 305static int 306pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin) 307{ 308 devclass_t pci_devclass; 309 device_t *pci_devices; 310 int pci_count; 311 device_t *pci_children; 312 int pci_childcount; 313 device_t *busp, *childp; 314 int i, j, irq; 315 316 /* 317 * Find all the PCI busses. 318 */ 319 pci_count = 0; 320 if ((pci_devclass = devclass_find("pci")) != NULL) 321 devclass_get_devices(pci_devclass, &pci_devices, &pci_count); 322 323 /* 324 * Scan all the PCI busses/devices looking for this one. 325 */ 326 for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) { 327 pci_childcount = 0; 328 device_get_children(*busp, &pci_children, &pci_childcount); 329 330 for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) { 331 if ((pci_get_bus(*childp) == bus) && 332 (pci_get_slot(*childp) == device) && 333 (pci_get_intpin(*childp) == matchpin) && 334 ((irq = pci_get_irq(*childp)) != 255)) { 335 printf("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", 336 irq, pe->pe_intpin[pin - 1].link, 337 pci_get_bus(*childp), pci_get_slot(*childp), pci_get_function(*childp)); 338 return(irq); 339 } 340 } 341 } 342 return(255); 343} 344 345/* 346 * Pick a suitable IRQ from those listed as routable to this device. 347 */ 348static int 349pci_cfgintr_virgin(struct PIR_entry *pe, int pin) 350{ 351 int irq, ibit; 352 353 /* first scan the set of PCI-only interrupts and see if any of these are routable */ 354 for (irq = 0; irq < 16; irq++) { 355 ibit = (1 << irq); 356 357 /* can we use this interrupt? */ 358 if ((pci_route_table->pt_header.ph_pci_irqs & ibit) && 359 (pe->pe_intpin[pin - 1].irqs & ibit)) { 360 printf("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq); 361 return(irq); 362 } 363 } 364 365 /* life is tough, so just pick an interrupt */ 366 for (irq = 0; irq < 16; irq++) { 367 ibit = (1 << irq); 368 369 if (pe->pe_intpin[pin - 1].irqs & ibit) { 370 printf("pci_cfgintr_virgin: using routable interrupt %d\n", irq); 371 return(irq); 372 } 373 } 374 return(255); 375} 376 377 378/* 379 * Config space access using BIOS functions 380 */ 381static int 382pcibios_cfgread(int bus, int slot, int func, int reg, int bytes) 383{ 384 struct bios_regs args; 385 u_int mask; 386 387 switch(bytes) { 388 case 1: 389 args.eax = PCIBIOS_READ_CONFIG_BYTE; 390 mask = 0xff; 391 break; 392 case 2: 393 args.eax = PCIBIOS_READ_CONFIG_WORD; 394 mask = 0xffff; 395 break; 396 case 4: 397 args.eax = PCIBIOS_READ_CONFIG_DWORD; 398 mask = 0xffffffff; 399 break; 400 default: 401 return(-1); 402 } 403 args.ebx = (bus << 8) | (slot << 3) | func; 404 args.edi = reg; 405 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 406 /* check call results? */ 407 return(args.ecx & mask); 408} 409 410static void 411pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 412{ 413 struct bios_regs args; 414 415 switch(bytes) { 416 case 1: 417 args.eax = PCIBIOS_WRITE_CONFIG_BYTE; 418 break; 419 case 2: 420 args.eax = PCIBIOS_WRITE_CONFIG_WORD; 421 break; 422 case 4: 423 args.eax = PCIBIOS_WRITE_CONFIG_DWORD; 424 break; 425 default: 426 return; 427 } 428 args.ebx = (bus << 8) | (slot << 3) | func; 429 args.ecx = data; 430 args.edi = reg; 431 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 432} 433 434/* 435 * Determine whether there is a PCI BIOS present 436 */ 437static int 438pcibios_cfgopen(void) 439{ 440 /* check for a found entrypoint */ 441 return(PCIbios.entry != 0); 442} 443 444/* 445 * Configuration space access using direct register operations 446 */ 447 448/* enable configuration space accesses and return data port address */ 449static int 450pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 451{ 452 int dataport = 0; 453 454 if (bus <= PCI_BUSMAX 455 && slot < devmax 456 && func <= PCI_FUNCMAX 457 && reg <= PCI_REGMAX 458 && bytes != 3 459 && (unsigned) bytes <= 4 460 && (reg & (bytes -1)) == 0) { 461 switch (cfgmech) { 462 case 1: 463 outl(CONF1_ADDR_PORT, (1 << 31) 464 | (bus << 16) | (slot << 11) 465 | (func << 8) | (reg & ~0x03)); 466 dataport = CONF1_DATA_PORT + (reg & 0x03); 467 break; 468 case 2: 469 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 470 outb(CONF2_FORWARD_PORT, bus); 471 dataport = 0xc000 | (slot << 8) | reg; 472 break; 473 } 474 } 475 return (dataport); 476} 477 478/* disable configuration space accesses */ 479static void 480pci_cfgdisable(void) 481{ 482 switch (cfgmech) { 483 case 1: 484 outl(CONF1_ADDR_PORT, 0); 485 break; 486 case 2: 487 outb(CONF2_ENABLE_PORT, 0); 488 outb(CONF2_FORWARD_PORT, 0); 489 break; 490 } 491} 492 493static int 494pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 495{ 496 int data = -1; 497 int port; 498 499 port = pci_cfgenable(bus, slot, func, reg, bytes); 500 501 if (port != 0) { 502 switch (bytes) { 503 case 1: 504 data = inb(port); 505 break; 506 case 2: 507 data = inw(port); 508 break; 509 case 4: 510 data = inl(port); 511 break; 512 } 513 pci_cfgdisable(); 514 } 515 return (data); 516} 517 518static void 519pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 520{ 521 int port; 522 523 port = pci_cfgenable(bus, slot, func, reg, bytes); 524 if (port != 0) { 525 switch (bytes) { 526 case 1: 527 outb(port, data); 528 break; 529 case 2: 530 outw(port, data); 531 break; 532 case 4: 533 outl(port, data); 534 break; 535 } 536 pci_cfgdisable(); 537 } 538} 539 540/* check whether the configuration mechanism has been correctly identified */ 541static int 542pci_cfgcheck(int maxdev) 543{ 544 u_char device; 545 546 if (bootverbose) 547 printf("pci_cfgcheck:\tdevice "); 548 549 for (device = 0; device < maxdev; device++) { 550 unsigned id, class, header; 551 if (bootverbose) 552 printf("%d ", device); 553 554 id = inl(pci_cfgenable(0, device, 0, 0, 4)); 555 if (id == 0 || id == -1) 556 continue; 557 558 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 559 if (bootverbose) 560 printf("[class=%06x] ", class); 561 if (class == 0 || (class & 0xf870ff) != 0) 562 continue; 563 564 header = inb(pci_cfgenable(0, device, 0, 14, 1)); 565 if (bootverbose) 566 printf("[hdr=%02x] ", header); 567 if ((header & 0x7e) != 0) 568 continue; 569 570 if (bootverbose) 571 printf("is there (id=%08x)\n", id); 572 573 pci_cfgdisable(); 574 return (1); 575 } 576 if (bootverbose) 577 printf("-- nothing found\n"); 578 579 pci_cfgdisable(); 580 return (0); 581} 582 583static int 584pcireg_cfgopen(void) 585{ 586 unsigned long mode1res,oldval1; 587 unsigned char mode2res,oldval2; 588 589 oldval1 = inl(CONF1_ADDR_PORT); 590 591 if (bootverbose) { 592 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 593 oldval1); 594 } 595 596 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 597 598 cfgmech = 1; 599 devmax = 32; 600 601 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 602 outb(CONF1_ADDR_PORT +3, 0); 603 mode1res = inl(CONF1_ADDR_PORT); 604 outl(CONF1_ADDR_PORT, oldval1); 605 606 if (bootverbose) 607 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 608 mode1res, CONF1_ENABLE_CHK); 609 610 if (mode1res) { 611 if (pci_cfgcheck(32)) 612 return (cfgmech); 613 } 614 615 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 616 mode1res = inl(CONF1_ADDR_PORT); 617 outl(CONF1_ADDR_PORT, oldval1); 618 619 if (bootverbose) 620 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 621 mode1res, CONF1_ENABLE_CHK1); 622 623 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 624 if (pci_cfgcheck(32)) 625 return (cfgmech); 626 } 627 } 628 629 oldval2 = inb(CONF2_ENABLE_PORT); 630 631 if (bootverbose) { 632 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 633 oldval2); 634 } 635 636 if ((oldval2 & 0xf0) == 0) { 637 638 cfgmech = 2; 639 devmax = 16; 640 641 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 642 mode2res = inb(CONF2_ENABLE_PORT); 643 outb(CONF2_ENABLE_PORT, oldval2); 644 645 if (bootverbose) 646 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 647 mode2res, CONF2_ENABLE_CHK); 648 649 if (mode2res == CONF2_ENABLE_RES) { 650 if (bootverbose) 651 printf("pci_open(2a):\tnow trying mechanism 2\n"); 652 653 if (pci_cfgcheck(16)) 654 return (cfgmech); 655 } 656 } 657 658 cfgmech = 0; 659 devmax = 0; 660 return (cfgmech); 661} 662 663