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