pci_cfgreg.c revision 181933
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 * Copyright (c) 2004, Scott Long <scottl@freebsd.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 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/i386/pci/pci_cfgreg.c 181933 2008-08-20 18:18:17Z jhb $"); 32 33#include "opt_xbox.h" 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/lock.h> 39#include <sys/mutex.h> 40#include <sys/malloc.h> 41#include <sys/queue.h> 42#include <dev/pci/pcivar.h> 43#include <dev/pci/pcireg.h> 44#include <machine/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#ifdef XBOX 55#include <machine/xbox.h> 56#endif 57 58#define PRVERB(a) do { \ 59 if (bootverbose) \ 60 printf a ; \ 61} while(0) 62 63#define PCIE_CACHE 8 64struct pcie_cfg_elem { 65 TAILQ_ENTRY(pcie_cfg_elem) elem; 66 vm_offset_t vapage; 67 vm_paddr_t papage; 68}; 69 70enum { 71 CFGMECH_NONE = 0, 72 CFGMECH_1, 73 CFGMECH_2, 74 CFGMECH_PCIE, 75}; 76 77static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU]; 78static uint64_t pciebar; 79static int cfgmech; 80static int devmax; 81static struct mtx pcicfg_mtx; 82 83static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); 84static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); 85#ifndef XEN 86static int pcireg_cfgopen(void); 87 88static int pciereg_cfgopen(void); 89#endif 90static int pciereg_cfgread(int bus, int slot, int func, int reg, 91 int bytes); 92static void pciereg_cfgwrite(int bus, int slot, int func, int reg, 93 int data, int bytes); 94 95/* 96 * Some BIOS writers seem to want to ignore the spec and put 97 * 0 in the intline rather than 255 to indicate none. Some use 98 * numbers in the range 128-254 to indicate something strange and 99 * apparently undocumented anywhere. Assume these are completely bogus 100 * and map them to 255, which means "none". 101 */ 102static __inline int 103pci_i386_map_intline(int line) 104{ 105 if (line == 0 || line >= 128) 106 return (PCI_INVALID_IRQ); 107 return (line); 108} 109 110#ifndef XEN 111static u_int16_t 112pcibios_get_version(void) 113{ 114 struct bios_regs args; 115 116 if (PCIbios.ventry == 0) { 117 PRVERB(("pcibios: No call entry point\n")); 118 return (0); 119 } 120 args.eax = PCIBIOS_BIOS_PRESENT; 121 if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { 122 PRVERB(("pcibios: BIOS_PRESENT call failed\n")); 123 return (0); 124 } 125 if (args.edx != 0x20494350) { 126 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n")); 127 return (0); 128 } 129 return (args.ebx & 0xffff); 130} 131#endif 132 133/* 134 * Initialise access to PCI configuration space 135 */ 136int 137pci_cfgregopen(void) 138{ 139#ifdef XEN 140 return (0); 141#else 142 static int opened = 0; 143 u_int16_t vid, did; 144 u_int16_t v; 145 146 if (opened) 147 return(1); 148 149 if (pcireg_cfgopen() == 0) 150 return(0); 151 152 v = pcibios_get_version(); 153 if (v > 0) 154 PRVERB(("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8, 155 v & 0xff)); 156 mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); 157 opened = 1; 158 159 /* $PIR requires PCI BIOS 2.10 or greater. */ 160 if (v >= 0x0210) 161 pci_pir_open(); 162 163 /* 164 * Grope around in the PCI config space to see if this is a 165 * chipset that is capable of doing memory-mapped config cycles. 166 * This also implies that it can do PCIe extended config cycles. 167 */ 168 169 /* Check for supported chipsets */ 170 vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2); 171 did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2); 172 switch (vid) { 173 case 0x8086: 174 switch (did) { 175 case 0x3590: 176 case 0x3592: 177 /* Intel 7520 or 7320 */ 178 pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; 179 pciereg_cfgopen(); 180 break; 181 case 0x2580: 182 case 0x2584: 183 case 0x2590: 184 /* Intel 915, 925, or 915GM */ 185 pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); 186 pciereg_cfgopen(); 187 break; 188 case 0x25d0: 189 case 0x25d4: 190 case 0x25d8: 191 /* Intel 5000Z/V/P */ 192 pciebar = pci_cfgregread(0, 16, 0, 0x64, 4) << 16; 193 pciereg_cfgopen(); 194 break; 195 } 196 } 197 198 return(1); 199#endif 200} 201 202/* 203 * Read configuration space register 204 */ 205u_int32_t 206pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 207{ 208 uint32_t line; 209 210 /* 211 * Some BIOS writers seem to want to ignore the spec and put 212 * 0 in the intline rather than 255 to indicate none. The rest of 213 * the code uses 255 as an invalid IRQ. 214 */ 215 if (reg == PCIR_INTLINE && bytes == 1) { 216 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); 217 return (pci_i386_map_intline(line)); 218 } 219 return (pcireg_cfgread(bus, slot, func, reg, bytes)); 220} 221 222/* 223 * Write configuration space register 224 */ 225void 226pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 227{ 228 229 pcireg_cfgwrite(bus, slot, func, reg, data, bytes); 230} 231 232/* 233 * Configuration space access using direct register operations 234 */ 235 236/* enable configuration space accesses and return data port address */ 237static int 238pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 239{ 240 int dataport = 0; 241 242#ifdef XBOX 243 if (arch_i386_is_xbox) { 244 /* 245 * The Xbox MCPX chipset is a derivative of the nForce 1 246 * chipset. It almost has the same bus layout; some devices 247 * cannot be used, because they have been removed. 248 */ 249 250 /* 251 * Devices 00:00.1 and 00:00.2 used to be memory controllers on 252 * the nForce chipset, but on the Xbox, using them will lockup 253 * the chipset. 254 */ 255 if (bus == 0 && slot == 0 && (func == 1 || func == 2)) 256 return dataport; 257 258 /* 259 * Bus 1 only contains a VGA controller at 01:00.0. When you try 260 * to probe beyond that device, you only get garbage, which 261 * could cause lockups. 262 */ 263 if (bus == 1 && (slot != 0 || func != 0)) 264 return dataport; 265 266 /* 267 * Bus 2 used to contain the AGP controller, but the Xbox MCPX 268 * doesn't have one. Probing it can cause lockups. 269 */ 270 if (bus >= 2) 271 return dataport; 272 } 273#endif 274 275 if (bus <= PCI_BUSMAX 276 && slot < devmax 277 && func <= PCI_FUNCMAX 278 && reg <= PCI_REGMAX 279 && bytes != 3 280 && (unsigned) bytes <= 4 281 && (reg & (bytes - 1)) == 0) { 282 switch (cfgmech) { 283 case CFGMECH_1: 284 outl(CONF1_ADDR_PORT, (1 << 31) 285 | (bus << 16) | (slot << 11) 286 | (func << 8) | (reg & ~0x03)); 287 dataport = CONF1_DATA_PORT + (reg & 0x03); 288 break; 289 case CFGMECH_2: 290 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 291 outb(CONF2_FORWARD_PORT, bus); 292 dataport = 0xc000 | (slot << 8) | reg; 293 break; 294 } 295 } 296 return (dataport); 297} 298 299/* disable configuration space accesses */ 300static void 301pci_cfgdisable(void) 302{ 303 switch (cfgmech) { 304 case CFGMECH_1: 305 /* 306 * Do nothing for the config mechanism 1 case. 307 * Writing a 0 to the address port can apparently 308 * confuse some bridges and cause spurious 309 * access failures. 310 */ 311 break; 312 case CFGMECH_2: 313 outb(CONF2_ENABLE_PORT, 0); 314 break; 315 } 316} 317 318static int 319pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 320{ 321 int data = -1; 322 int port; 323 324 if (cfgmech == CFGMECH_PCIE) { 325 data = pciereg_cfgread(bus, slot, func, reg, bytes); 326 return (data); 327 } 328 329 mtx_lock_spin(&pcicfg_mtx); 330 port = pci_cfgenable(bus, slot, func, reg, bytes); 331 if (port != 0) { 332 switch (bytes) { 333 case 1: 334 data = inb(port); 335 break; 336 case 2: 337 data = inw(port); 338 break; 339 case 4: 340 data = inl(port); 341 break; 342 } 343 pci_cfgdisable(); 344 } 345 mtx_unlock_spin(&pcicfg_mtx); 346 return (data); 347} 348 349static void 350pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 351{ 352 int port; 353 354 if (cfgmech == CFGMECH_PCIE) { 355 pciereg_cfgwrite(bus, slot, func, reg, data, bytes); 356 return; 357 } 358 359 mtx_lock_spin(&pcicfg_mtx); 360 port = pci_cfgenable(bus, slot, func, reg, bytes); 361 if (port != 0) { 362 switch (bytes) { 363 case 1: 364 outb(port, data); 365 break; 366 case 2: 367 outw(port, data); 368 break; 369 case 4: 370 outl(port, data); 371 break; 372 } 373 pci_cfgdisable(); 374 } 375 mtx_unlock_spin(&pcicfg_mtx); 376} 377 378#ifndef XEN 379/* check whether the configuration mechanism has been correctly identified */ 380static int 381pci_cfgcheck(int maxdev) 382{ 383 uint32_t id, class; 384 uint8_t header; 385 uint8_t device; 386 int port; 387 388 if (bootverbose) 389 printf("pci_cfgcheck:\tdevice "); 390 391 for (device = 0; device < maxdev; device++) { 392 if (bootverbose) 393 printf("%d ", device); 394 395 port = pci_cfgenable(0, device, 0, 0, 4); 396 id = inl(port); 397 if (id == 0 || id == 0xffffffff) 398 continue; 399 400 port = pci_cfgenable(0, device, 0, 8, 4); 401 class = inl(port) >> 8; 402 if (bootverbose) 403 printf("[class=%06x] ", class); 404 if (class == 0 || (class & 0xf870ff) != 0) 405 continue; 406 407 port = pci_cfgenable(0, device, 0, 14, 1); 408 header = inb(port); 409 if (bootverbose) 410 printf("[hdr=%02x] ", header); 411 if ((header & 0x7e) != 0) 412 continue; 413 414 if (bootverbose) 415 printf("is there (id=%08x)\n", id); 416 417 pci_cfgdisable(); 418 return (1); 419 } 420 if (bootverbose) 421 printf("-- nothing found\n"); 422 423 pci_cfgdisable(); 424 return (0); 425} 426 427static int 428pcireg_cfgopen(void) 429{ 430 uint32_t mode1res, oldval1; 431 uint8_t mode2res, oldval2; 432 433 /* Check for type #1 first. */ 434 oldval1 = inl(CONF1_ADDR_PORT); 435 436 if (bootverbose) { 437 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n", 438 oldval1); 439 } 440 441 cfgmech = CFGMECH_1; 442 devmax = 32; 443 444 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 445 DELAY(1); 446 mode1res = inl(CONF1_ADDR_PORT); 447 outl(CONF1_ADDR_PORT, oldval1); 448 449 if (bootverbose) 450 printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", mode1res, 451 CONF1_ENABLE_CHK); 452 453 if (mode1res) { 454 if (pci_cfgcheck(32)) 455 return (cfgmech); 456 } 457 458 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 459 mode1res = inl(CONF1_ADDR_PORT); 460 outl(CONF1_ADDR_PORT, oldval1); 461 462 if (bootverbose) 463 printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", mode1res, 464 CONF1_ENABLE_CHK1); 465 466 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 467 if (pci_cfgcheck(32)) 468 return (cfgmech); 469 } 470 471 /* Type #1 didn't work, so try type #2. */ 472 oldval2 = inb(CONF2_ENABLE_PORT); 473 474 if (bootverbose) { 475 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 476 oldval2); 477 } 478 479 if ((oldval2 & 0xf0) == 0) { 480 481 cfgmech = CFGMECH_2; 482 devmax = 16; 483 484 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 485 mode2res = inb(CONF2_ENABLE_PORT); 486 outb(CONF2_ENABLE_PORT, oldval2); 487 488 if (bootverbose) 489 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 490 mode2res, CONF2_ENABLE_CHK); 491 492 if (mode2res == CONF2_ENABLE_RES) { 493 if (bootverbose) 494 printf("pci_open(2a):\tnow trying mechanism 2\n"); 495 496 if (pci_cfgcheck(16)) 497 return (cfgmech); 498 } 499 } 500 501 /* Nothing worked, so punt. */ 502 cfgmech = CFGMECH_NONE; 503 devmax = 0; 504 return (cfgmech); 505} 506 507static int 508pciereg_cfgopen(void) 509{ 510 struct pcie_cfg_list *pcielist; 511 struct pcie_cfg_elem *pcie_array, *elem; 512#ifdef SMP 513 struct pcpu *pc; 514#endif 515 vm_offset_t va; 516 int i; 517 518#ifndef PAE 519 if (pciebar >= 0x100000000) { 520 if (bootverbose) 521 printf( 522 "PCI: Memory Mapped PCI configuration area base 0x%jx too high\n", 523 (uintmax_t)pciebar); 524 pciebar = 0; 525 return (0); 526 } 527#endif 528 529 if (bootverbose) 530 printf("Setting up PCIe mappings for BAR 0x%jx\n", 531 (uintmax_t)pciebar); 532 533#ifdef SMP 534 SLIST_FOREACH(pc, &cpuhead, pc_allcpu) 535#endif 536 { 537 538 pcie_array = malloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE, 539 M_DEVBUF, M_NOWAIT); 540 if (pcie_array == NULL) 541 return (0); 542 543 va = kmem_alloc_nofault(kernel_map, PCIE_CACHE * PAGE_SIZE); 544 if (va == 0) { 545 free(pcie_array, M_DEVBUF); 546 return (0); 547 } 548 549#ifdef SMP 550 pcielist = &pcie_list[pc->pc_cpuid]; 551#else 552 pcielist = &pcie_list[0]; 553#endif 554 TAILQ_INIT(pcielist); 555 for (i = 0; i < PCIE_CACHE; i++) { 556 elem = &pcie_array[i]; 557 elem->vapage = va + (i * PAGE_SIZE); 558 elem->papage = 0; 559 TAILQ_INSERT_HEAD(pcielist, elem, elem); 560 } 561 } 562 563 564 cfgmech = CFGMECH_PCIE; 565 devmax = 32; 566 return (1); 567} 568#endif /* !XEN */ 569 570#define PCIE_PADDR(bar, reg, bus, slot, func) \ 571 ((bar) | \ 572 (((bus) & 0xff) << 20) | \ 573 (((slot) & 0x1f) << 15) | \ 574 (((func) & 0x7) << 12) | \ 575 ((reg) & 0xfff)) 576 577/* 578 * Find an element in the cache that matches the physical page desired, or 579 * create a new mapping from the least recently used element. 580 * A very simple LRU algorithm is used here, does it need to be more 581 * efficient? 582 */ 583static __inline struct pcie_cfg_elem * 584pciereg_findelem(vm_paddr_t papage) 585{ 586 struct pcie_cfg_list *pcielist; 587 struct pcie_cfg_elem *elem; 588 589 pcielist = &pcie_list[PCPU_GET(cpuid)]; 590 TAILQ_FOREACH(elem, pcielist, elem) { 591 if (elem->papage == papage) 592 break; 593 } 594 595 if (elem == NULL) { 596 elem = TAILQ_LAST(pcielist, pcie_cfg_list); 597 if (elem->papage != 0) { 598 pmap_kremove(elem->vapage); 599 invlpg(elem->vapage); 600 } 601 pmap_kenter(elem->vapage, papage); 602 elem->papage = papage; 603 } 604 605 if (elem != TAILQ_FIRST(pcielist)) { 606 TAILQ_REMOVE(pcielist, elem, elem); 607 TAILQ_INSERT_HEAD(pcielist, elem, elem); 608 } 609 return (elem); 610} 611 612static int 613pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) 614{ 615 struct pcie_cfg_elem *elem; 616 volatile vm_offset_t va; 617 vm_paddr_t pa, papage; 618 int data; 619 620 critical_enter(); 621 pa = PCIE_PADDR(pciebar, reg, bus, slot, func); 622 papage = pa & ~PAGE_MASK; 623 elem = pciereg_findelem(papage); 624 va = elem->vapage | (pa & PAGE_MASK); 625 626 switch (bytes) { 627 case 4: 628 data = *(volatile uint32_t *)(va); 629 break; 630 case 2: 631 data = *(volatile uint16_t *)(va); 632 break; 633 case 1: 634 data = *(volatile uint8_t *)(va); 635 break; 636 default: 637 panic("pciereg_cfgread: invalid width"); 638 } 639 640 critical_exit(); 641 return (data); 642} 643 644static void 645pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 646{ 647 struct pcie_cfg_elem *elem; 648 volatile vm_offset_t va; 649 vm_paddr_t pa, papage; 650 651 critical_enter(); 652 pa = PCIE_PADDR(pciebar, reg, bus, slot, func); 653 papage = pa & ~PAGE_MASK; 654 elem = pciereg_findelem(papage); 655 va = elem->vapage | (pa & PAGE_MASK); 656 657 switch (bytes) { 658 case 4: 659 *(volatile uint32_t *)(va) = data; 660 break; 661 case 2: 662 *(volatile uint16_t *)(va) = data; 663 break; 664 case 1: 665 *(volatile uint8_t *)(va) = data; 666 break; 667 default: 668 panic("pciereg_cfgwrite: invalid width"); 669 } 670 671 critical_exit(); 672} 673