1 /*- 2 * Copyright (c) 1997, Stefan Esser <se@kfreebsd.org> 3 * Copyright (c) 2000, Michael Smith <msmith@kfreebsd.org> 4 * Copyright (c) 2000, BSDi 5 * Copyright (c) 2004, Scott Long <scottl@kfreebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice unmodified, this list of conditions, and the following 13 * disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.124.2.3 2009/05/04 21:04:29 jhb 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.h> 37 #include <sys/malloc.h> 38 #include <sys/thread2.h> 39 #include <sys/spinlock.h> 40 #include <sys/spinlock2.h> 41 #include <sys/queue.h> 42 #include <bus/pci/pcivar.h> 43 #include <bus/pci/pcireg.h> 44 #include "pci_cfgreg.h" 45 #include <machine/pc/bios.h> 46 47 #include <vm/vm.h> 48 #include <vm/vm_param.h> 49 #include <vm/vm_kern.h> 50 #include <vm/vm_extern.h> 51 #include <vm/pmap.h> 52 #include <machine/pmap.h> 53 54 #if defined(__DragonFly__) 55 #define mtx_init(a, b, c, d) spin_init(a) 56 #define mtx_lock_spin(a) spin_lock_wr(a) 57 #define mtx_unlock_spin(a) spin_unlock_wr(a) 58 #endif 59 60 #define PRVERB(a) do { \ 61 if (bootverbose) \ 62 kprintf a ; \ 63 } while(0) 64 65 #define PCIE_CACHE 8 66 struct pcie_cfg_elem { 67 TAILQ_ENTRY(pcie_cfg_elem) elem; 68 vm_offset_t vapage; 69 vm_paddr_t papage; 70 }; 71 72 enum { 73 CFGMECH_NONE = 0, 74 CFGMECH_1, 75 CFGMECH_2, 76 CFGMECH_PCIE, 77 }; 78 79 static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU]; 80 static uint64_t pcie_base; 81 static int pcie_minbus, pcie_maxbus; 82 static uint32_t pcie_badslots; 83 static int cfgmech; 84 static int devmax; 85 #if defined(__DragonFly__) 86 static struct spinlock pcicfg_mtx; 87 #else 88 static struct mtx pcicfg_mtx; 89 #endif 90 static int mcfg_enable = 0; 91 92 TUNABLE_INT("hw.pci.mcfg", &mcfg_enable); 93 94 static uint32_t pci_docfgregread(int bus, int slot, int func, int reg, int bytes); 95 static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); 96 static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); 97 static int pcireg_cfgopen(void); 98 99 static int pciereg_cfgread(int bus, unsigned slot, unsigned func, 100 unsigned reg, unsigned bytes); 101 static void pciereg_cfgwrite(int bus, unsigned slot, unsigned func, 102 unsigned reg, int data, unsigned bytes); 103 104 105 106 /* 107 * Some BIOS writers seem to want to ignore the spec and put 108 * 0 in the intline rather than 255 to indicate none. Some use 109 * numbers in the range 128-254 to indicate something strange and 110 * apparently undocumented anywhere. Assume these are completely bogus 111 * and map them to 255, which means "none". 112 */ 113 static __inline int 114 pci_i386_map_intline(int line) 115 { 116 if (line == 0 || line >= 128) 117 return (PCI_INVALID_IRQ); 118 return (line); 119 } 120 121 #ifdef notyet 122 123 static u_int16_t 124 pcibios_get_version(void) 125 { 126 struct bios_regs args; 127 128 if (PCIbios.ventry == 0) { 129 PRVERB(("pcibios: No call entry point\n")); 130 return (0); 131 } 132 args.eax = PCIBIOS_BIOS_PRESENT; 133 if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { 134 PRVERB(("pcibios: BIOS_PRESENT call failed\n")); 135 return (0); 136 } 137 if (args.edx != 0x20494350) { 138 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n")); 139 return (0); 140 } 141 return (args.ebx & 0xffff); 142 } 143 144 #endif 145 146 /* 147 * Initialise access to PCI configuration space 148 */ 149 int 150 pci_cfgregopen(void) 151 { 152 static int opened = 0; 153 #ifdef notyet 154 u_int16_t vid, did; 155 u_int16_t v; 156 #endif 157 158 if (opened) 159 return(1); 160 161 if (pcireg_cfgopen() == 0) 162 return(0); 163 164 #ifdef notyet 165 v = pcibios_get_version(); 166 if (v > 0) 167 PRVERB(("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8, 168 v & 0xff)); 169 mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); 170 opened = 1; 171 172 /* $PIR requires PCI BIOS 2.10 or greater. */ 173 if (v >= 0x0210) 174 pci_pir_open(); 175 176 if (cfgmech == CFGMECH_PCIE) 177 return (1); 178 179 /* 180 * Grope around in the PCI config space to see if this is a 181 * chipset that is capable of doing memory-mapped config cycles. 182 * This also implies that it can do PCIe extended config cycles. 183 */ 184 185 /* Check for supported chipsets */ 186 vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2); 187 did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2); 188 switch (vid) { 189 case 0x8086: 190 switch (did) { 191 case 0x3590: 192 case 0x3592: 193 /* Intel 7520 or 7320 */ 194 pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; 195 pcie_cfgregopen(pciebar, 0, 255); 196 break; 197 case 0x2580: 198 case 0x2584: 199 case 0x2590: 200 /* Intel 915, 925, or 915GM */ 201 pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); 202 pcie_cfgregopen(pciebar, 0, 255); 203 break; 204 } 205 } 206 207 #else 208 opened = 1; 209 #endif 210 return(1); 211 } 212 213 static uint32_t 214 pci_docfgregread(int bus, int slot, int func, int reg, int bytes) 215 { 216 217 if (cfgmech == CFGMECH_PCIE && 218 (bus >= pcie_minbus && bus <= pcie_maxbus) && 219 (bus != 0 || !(1 << slot & pcie_badslots))) 220 return (pciereg_cfgread(bus, slot, func, reg, bytes)); 221 else 222 return (pcireg_cfgread(bus, slot, func, reg, bytes)); 223 } 224 225 /* 226 * Read configuration space register 227 */ 228 u_int32_t 229 pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 230 { 231 uint32_t line; 232 233 /* 234 * Some BIOS writers seem to want to ignore the spec and put 235 * 0 in the intline rather than 255 to indicate none. The rest of 236 * the code uses 255 as an invalid IRQ. 237 */ 238 if (reg == PCIR_INTLINE && bytes == 1) { 239 line = pci_docfgregread(bus, slot, func, PCIR_INTLINE, 1); 240 return (pci_i386_map_intline(line)); 241 } 242 return (pci_docfgregread(bus, slot, func, reg, bytes)); 243 } 244 245 /* 246 * Write configuration space register 247 */ 248 void 249 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 250 { 251 252 if (cfgmech == CFGMECH_PCIE && 253 (bus >= pcie_minbus && bus <= pcie_maxbus) && 254 (bus != 0 || !(1 << slot & pcie_badslots))) 255 pciereg_cfgwrite(bus, slot, func, reg, data, bytes); 256 else 257 pcireg_cfgwrite(bus, slot, func, reg, data, bytes); 258 } 259 260 /* 261 * Configuration space access using direct register operations 262 */ 263 264 /* enable configuration space accesses and return data port address */ 265 static int 266 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 267 { 268 int dataport = 0; 269 270 #ifdef XBOX 271 if (arch_i386_is_xbox) { 272 /* 273 * The Xbox MCPX chipset is a derivative of the nForce 1 274 * chipset. It almost has the same bus layout; some devices 275 * cannot be used, because they have been removed. 276 */ 277 278 /* 279 * Devices 00:00.1 and 00:00.2 used to be memory controllers on 280 * the nForce chipset, but on the Xbox, using them will lockup 281 * the chipset. 282 */ 283 if (bus == 0 && slot == 0 && (func == 1 || func == 2)) 284 return dataport; 285 286 /* 287 * Bus 1 only contains a VGA controller at 01:00.0. When you try 288 * to probe beyond that device, you only get garbage, which 289 * could cause lockups. 290 */ 291 if (bus == 1 && (slot != 0 || func != 0)) 292 return dataport; 293 294 /* 295 * Bus 2 used to contain the AGP controller, but the Xbox MCPX 296 * doesn't have one. Probing it can cause lockups. 297 */ 298 if (bus >= 2) 299 return dataport; 300 } 301 #endif 302 303 if (bus <= PCI_BUSMAX 304 && slot < devmax 305 && func <= PCI_FUNCMAX 306 && reg <= PCI_REGMAX 307 && bytes != 3 308 && (unsigned) bytes <= 4 309 && (reg & (bytes - 1)) == 0) { 310 switch (cfgmech) { 311 case CFGMECH_PCIE: 312 case CFGMECH_1: 313 outl(CONF1_ADDR_PORT, (1 << 31) 314 | (bus << 16) | (slot << 11) 315 | (func << 8) | (reg & ~0x03)); 316 dataport = CONF1_DATA_PORT + (reg & 0x03); 317 break; 318 case CFGMECH_2: 319 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 320 outb(CONF2_FORWARD_PORT, bus); 321 dataport = 0xc000 | (slot << 8) | reg; 322 break; 323 } 324 } 325 return (dataport); 326 } 327 328 /* disable configuration space accesses */ 329 static void 330 pci_cfgdisable(void) 331 { 332 switch (cfgmech) { 333 case CFGMECH_PCIE: 334 case CFGMECH_1: 335 /* 336 * Do nothing for the config mechanism 1 case. 337 * Writing a 0 to the address port can apparently 338 * confuse some bridges and cause spurious 339 * access failures. 340 */ 341 break; 342 case CFGMECH_2: 343 outb(CONF2_ENABLE_PORT, 0); 344 break; 345 } 346 } 347 348 static int 349 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 350 { 351 int data = -1; 352 int port; 353 354 mtx_lock_spin(&pcicfg_mtx); 355 port = pci_cfgenable(bus, slot, func, reg, bytes); 356 if (port != 0) { 357 switch (bytes) { 358 case 1: 359 data = inb(port); 360 break; 361 case 2: 362 data = inw(port); 363 break; 364 case 4: 365 data = inl(port); 366 break; 367 } 368 pci_cfgdisable(); 369 } 370 mtx_unlock_spin(&pcicfg_mtx); 371 return (data); 372 } 373 374 static void 375 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 376 { 377 int port; 378 379 mtx_lock_spin(&pcicfg_mtx); 380 port = pci_cfgenable(bus, slot, func, reg, bytes); 381 if (port != 0) { 382 switch (bytes) { 383 case 1: 384 outb(port, data); 385 break; 386 case 2: 387 outw(port, data); 388 break; 389 case 4: 390 outl(port, data); 391 break; 392 } 393 pci_cfgdisable(); 394 } 395 mtx_unlock_spin(&pcicfg_mtx); 396 } 397 398 /* check whether the configuration mechanism has been correctly identified */ 399 static int 400 pci_cfgcheck(int maxdev) 401 { 402 uint32_t id, class; 403 uint8_t header; 404 uint8_t device; 405 int port; 406 407 if (bootverbose) 408 kprintf("pci_cfgcheck:\tdevice "); 409 410 for (device = 0; device < maxdev; device++) { 411 if (bootverbose) 412 kprintf("%d ", device); 413 414 port = pci_cfgenable(0, device, 0, 0, 4); 415 id = inl(port); 416 if (id == 0 || id == 0xffffffff) 417 continue; 418 419 port = pci_cfgenable(0, device, 0, 8, 4); 420 class = inl(port) >> 8; 421 if (bootverbose) 422 kprintf("[class=%06x] ", class); 423 if (class == 0 || (class & 0xf870ff) != 0) 424 continue; 425 426 port = pci_cfgenable(0, device, 0, 14, 1); 427 header = inb(port); 428 if (bootverbose) 429 kprintf("[hdr=%02x] ", header); 430 if ((header & 0x7e) != 0) 431 continue; 432 433 if (bootverbose) 434 kprintf("is there (id=%08x)\n", id); 435 436 pci_cfgdisable(); 437 return (1); 438 } 439 if (bootverbose) 440 kprintf("-- nothing found\n"); 441 442 pci_cfgdisable(); 443 return (0); 444 } 445 446 static int 447 pcireg_cfgopen(void) 448 { 449 uint32_t mode1res, oldval1; 450 uint8_t mode2res, oldval2; 451 452 /* Check for type #1 first. */ 453 oldval1 = inl(CONF1_ADDR_PORT); 454 455 if (bootverbose) { 456 kprintf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n", 457 oldval1); 458 } 459 460 cfgmech = CFGMECH_1; 461 devmax = 32; 462 463 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 464 DELAY(1); 465 mode1res = inl(CONF1_ADDR_PORT); 466 outl(CONF1_ADDR_PORT, oldval1); 467 468 if (bootverbose) 469 kprintf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", mode1res, 470 CONF1_ENABLE_CHK); 471 472 if (mode1res) { 473 if (pci_cfgcheck(32)) 474 return (cfgmech); 475 } 476 477 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 478 mode1res = inl(CONF1_ADDR_PORT); 479 outl(CONF1_ADDR_PORT, oldval1); 480 481 if (bootverbose) 482 kprintf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", mode1res, 483 CONF1_ENABLE_CHK1); 484 485 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 486 if (pci_cfgcheck(32)) 487 return (cfgmech); 488 } 489 490 /* Type #1 didn't work, so try type #2. */ 491 oldval2 = inb(CONF2_ENABLE_PORT); 492 493 if (bootverbose) { 494 kprintf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 495 oldval2); 496 } 497 498 if ((oldval2 & 0xf0) == 0) { 499 500 cfgmech = CFGMECH_2; 501 devmax = 16; 502 503 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 504 mode2res = inb(CONF2_ENABLE_PORT); 505 outb(CONF2_ENABLE_PORT, oldval2); 506 507 if (bootverbose) 508 kprintf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 509 mode2res, CONF2_ENABLE_CHK); 510 511 if (mode2res == CONF2_ENABLE_RES) { 512 if (bootverbose) 513 kprintf("pci_open(2a):\tnow trying mechanism 2\n"); 514 515 if (pci_cfgcheck(16)) 516 return (cfgmech); 517 } 518 } 519 520 /* Nothing worked, so punt. */ 521 cfgmech = CFGMECH_NONE; 522 devmax = 0; 523 return (cfgmech); 524 } 525 526 int 527 pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus) 528 { 529 #ifdef PCIE_CFG_MECH 530 struct pcie_cfg_list *pcielist; 531 struct pcie_cfg_elem *pcie_array, *elem; 532 #ifdef SMP 533 struct pcpu *pc; 534 #endif 535 vm_offset_t va; 536 uint32_t val1, val2; 537 int i, slot; 538 539 if (!mcfg_enable) 540 return (0); 541 542 if (minbus != 0) 543 return (0); 544 545 if (base >= 0x100000000) { 546 if (bootverbose) 547 kprintf( 548 "PCI: Memory Mapped PCI configuration area base 0x%jx too high\n", 549 (uintmax_t)base); 550 return (0); 551 } 552 553 if (bootverbose) 554 kprintf("PCIe: Memory Mapped configuration base @ 0x%jx\n", 555 (uintmax_t)base); 556 557 #ifdef SMP 558 SLIST_FOREACH(pc, &cpuhead, pc_allcpu) 559 #endif 560 { 561 562 pcie_array = kmalloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE, 563 M_DEVBUF, M_NOWAIT); 564 if (pcie_array == NULL) 565 return (0); 566 567 va = kmem_alloc_nofault(&kernel_map, PCIE_CACHE * PAGE_SIZE, 568 PAGE_SIZE); 569 if (va == 0) { 570 kfree(pcie_array, M_DEVBUF); 571 return (0); 572 } 573 574 #ifdef SMP 575 pcielist = &pcie_list[pc->pc_cpuid]; 576 #else 577 pcielist = &pcie_list[0]; 578 #endif 579 TAILQ_INIT(pcielist); 580 for (i = 0; i < PCIE_CACHE; i++) { 581 elem = &pcie_array[i]; 582 elem->vapage = va + (i * PAGE_SIZE); 583 elem->papage = 0; 584 TAILQ_INSERT_HEAD(pcielist, elem, elem); 585 } 586 } 587 588 pcie_base = base; 589 pcie_minbus = minbus; 590 pcie_maxbus = maxbus; 591 cfgmech = CFGMECH_PCIE; 592 devmax = 32; 593 594 /* 595 * On some AMD systems, some of the devices on bus 0 are 596 * inaccessible using memory-mapped PCI config access. Walk 597 * bus 0 looking for such devices. For these devices, we will 598 * fall back to using type 1 config access instead. 599 */ 600 if (pci_cfgregopen() != 0) { 601 for (slot = 0; slot < 32; slot++) { 602 val1 = pcireg_cfgread(0, slot, 0, 0, 4); 603 if (val1 == 0xffffffff) 604 continue; 605 606 val2 = pciereg_cfgread(0, slot, 0, 0, 4); 607 if (val2 != val1) 608 pcie_badslots |= (1 << slot); 609 } 610 } 611 612 return (1); 613 #else /* !PCIE_CFG_MECH */ 614 return (0); 615 #endif /* PCIE_CFG_MECH */ 616 } 617 618 #define PCIE_PADDR(bar, reg, bus, slot, func) \ 619 ((bar) | \ 620 (((bus) & 0xff) << 20) | \ 621 (((slot) & 0x1f) << 15) | \ 622 (((func) & 0x7) << 12) | \ 623 ((reg) & 0xfff)) 624 625 /* 626 * Find an element in the cache that matches the physical page desired, or 627 * create a new mapping from the least recently used element. 628 * A very simple LRU algorithm is used here, does it need to be more 629 * efficient? 630 */ 631 static __inline struct pcie_cfg_elem * 632 pciereg_findelem(vm_paddr_t papage) 633 { 634 struct pcie_cfg_list *pcielist; 635 struct pcie_cfg_elem *elem; 636 pcielist = &pcie_list[mycpuid]; 637 TAILQ_FOREACH(elem, pcielist, elem) { 638 if (elem->papage == papage) 639 break; 640 } 641 642 if (elem == NULL) { 643 elem = TAILQ_LAST(pcielist, pcie_cfg_list); 644 if (elem->papage != 0) { 645 pmap_kremove(elem->vapage); 646 cpu_invlpg(&elem->vapage); 647 } 648 pmap_kenter(elem->vapage, papage); 649 elem->papage = papage; 650 } 651 652 if (elem != TAILQ_FIRST(pcielist)) { 653 TAILQ_REMOVE(pcielist, elem, elem); 654 TAILQ_INSERT_HEAD(pcielist, elem, elem); 655 } 656 return (elem); 657 } 658 659 static int 660 pciereg_cfgread(int bus, unsigned slot, unsigned func, unsigned reg, 661 unsigned bytes) 662 { 663 struct pcie_cfg_elem *elem; 664 volatile vm_offset_t va; 665 vm_paddr_t pa, papage; 666 int data = -1; 667 668 if (bus < pcie_minbus || bus > pcie_maxbus || slot >= 32 || 669 func > PCI_FUNCMAX || reg >= 0x1000 || bytes > 4 || bytes == 3) 670 return (-1); 671 672 crit_enter(); 673 pa = PCIE_PADDR(pcie_base, reg, bus, slot, func); 674 papage = pa & ~PAGE_MASK; 675 elem = pciereg_findelem(papage); 676 va = elem->vapage | (pa & PAGE_MASK); 677 678 switch (bytes) { 679 case 4: 680 data = *(volatile uint32_t *)(va); 681 break; 682 case 2: 683 data = *(volatile uint16_t *)(va); 684 break; 685 case 1: 686 data = *(volatile uint8_t *)(va); 687 break; 688 } 689 690 crit_exit(); 691 return (data); 692 } 693 694 static void 695 pciereg_cfgwrite(int bus, unsigned slot, unsigned func, unsigned reg, int data, unsigned bytes) 696 { 697 struct pcie_cfg_elem *elem; 698 volatile vm_offset_t va; 699 vm_paddr_t pa, papage; 700 701 crit_enter(); 702 pa = PCIE_PADDR(pcie_base, reg, bus, slot, func); 703 papage = pa & ~PAGE_MASK; 704 elem = pciereg_findelem(papage); 705 va = elem->vapage | (pa & PAGE_MASK); 706 707 switch (bytes) { 708 case 4: 709 *(volatile uint32_t *)(va) = data; 710 break; 711 case 2: 712 *(volatile uint16_t *)(va) = data; 713 break; 714 case 1: 715 *(volatile uint8_t *)(va) = data; 716 break; 717 } 718 719 crit_exit(); 720 } 721