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 the Intel 7520 and 925 chipsets */ 163 vid = pci_cfgregread(0, 0, 0, 0x0, 2); 164 did = pci_cfgregread(0, 0, 0, 0x2, 2); 165 if ((vid == 0x8086) && (did == 0x3590)) { 166 pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; 167 pciereg_cfgopen(); 168 } else if ((vid == 0x8086) && (did == 0x2580)) { 169 pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); 170 pciereg_cfgopen(); 171 } 172 173 return(1); 174 } 175 176 /* 177 * Read configuration space register 178 */ 179 u_int32_t 180 pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 181 { 182 uint32_t line; 183 184 /* 185 * Some BIOS writers seem to want to ignore the spec and put 186 * 0 in the intline rather than 255 to indicate none. The rest of 187 * the code uses 255 as an invalid IRQ. 188 */ 189 if (reg == PCIR_INTLINE && bytes == 1) { 190 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); 191 return (pci_i386_map_intline(line)); 192 } 193 return (pcireg_cfgread(bus, slot, func, reg, bytes)); 194 } 195 196 /* 197 * Write configuration space register 198 */ 199 void 200 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 201 { 202 203 pcireg_cfgwrite(bus, slot, func, reg, data, bytes); 204 } 205 206 /* 207 * Configuration space access using direct register operations 208 */ 209 210 /* enable configuration space accesses and return data port address */ 211 static int 212 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 213 { 214 int dataport = 0; 215 216 #ifdef XBOX 217 if (arch_i386_is_xbox) { 218 /* 219 * The Xbox MCPX chipset is a derivative of the nForce 1 220 * chipset. It almost has the same bus layout; some devices 221 * cannot be used, because they have been removed. 222 */ 223 224 /* 225 * Devices 00:00.1 and 00:00.2 used to be memory controllers on 226 * the nForce chipset, but on the Xbox, using them will lockup 227 * the chipset. 228 */ 229 if (bus == 0 && slot == 0 && (func == 1 || func == 2)) 230 return dataport; 231 232 /* 233 * Bus 1 only contains a VGA controller at 01:00.0. When you try 234 * to probe beyond that device, you only get garbage, which 235 * could cause lockups. 236 */ 237 if (bus == 1 && (slot != 0 || func != 0)) 238 return dataport; 239 240 /* 241 * Bus 2 used to contain the AGP controller, but the Xbox MCPX 242 * doesn't have one. Probing it can cause lockups. 243 */ 244 if (bus >= 2) 245 return dataport; 246 } 247 #endif 248 249 if (bus <= PCI_BUSMAX 250 && slot < devmax 251 && func <= PCI_FUNCMAX 252 && reg <= PCI_REGMAX 253 && bytes != 3 254 && (unsigned) bytes <= 4 255 && (reg & (bytes - 1)) == 0) { 256 switch (cfgmech) { 257 case CFGMECH_1: 258 outl(CONF1_ADDR_PORT, (1 << 31) 259 | (bus << 16) | (slot << 11) 260 | (func << 8) | (reg & ~0x03)); 261 dataport = CONF1_DATA_PORT + (reg & 0x03); 262 break; 263 case CFGMECH_2: 264 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 265 outb(CONF2_FORWARD_PORT, bus); 266 dataport = 0xc000 | (slot << 8) | reg; 267 break; 268 } 269 } 270 return (dataport); 271 } 272 273 /* disable configuration space accesses */ 274 static void 275 pci_cfgdisable(void) 276 { 277 switch (cfgmech) { 278 case CFGMECH_1: 279 outl(CONF1_ADDR_PORT, 0); 280 break; 281 case CFGMECH_2: 282 outb(CONF2_ENABLE_PORT, 0); 283 outb(CONF2_FORWARD_PORT, 0); 284 break; 285 } 286 } 287 288 static int 289 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 290 { 291 int data = -1; 292 int port; 293 294 if (cfgmech == CFGMECH_PCIE) { 295 data = pciereg_cfgread(bus, slot, func, reg, bytes); 296 return (data); 297 } 298 299 mtx_lock_spin(&pcicfg_mtx); 300 port = pci_cfgenable(bus, slot, func, reg, bytes); 301 if (port != 0) { 302 switch (bytes) { 303 case 1: 304 data = inb(port); 305 break; 306 case 2: 307 data = inw(port); 308 break; 309 case 4: 310 data = inl(port); 311 break; 312 } 313 pci_cfgdisable(); 314 } 315 mtx_unlock_spin(&pcicfg_mtx); 316 return (data); 317 } 318 319 static void 320 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 321 { 322 int port; 323 324 if (cfgmech == CFGMECH_PCIE) { 325 pciereg_cfgwrite(bus, slot, func, reg, data, bytes); 326 return; 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 outb(port, data); 335 break; 336 case 2: 337 outw(port, data); 338 break; 339 case 4: 340 outl(port, data); 341 break; 342 } 343 pci_cfgdisable(); 344 } 345 mtx_unlock_spin(&pcicfg_mtx); 346 } 347 348 /* check whether the configuration mechanism has been correctly identified */ 349 static int 350 pci_cfgcheck(int maxdev) 351 { 352 uint32_t id, class; 353 uint8_t header; 354 uint8_t device; 355 int port; 356 357 if (bootverbose) 358 printf("pci_cfgcheck:\tdevice "); 359 360 for (device = 0; device < maxdev; device++) { 361 if (bootverbose) 362 printf("%d ", device); 363 364 port = pci_cfgenable(0, device, 0, 0, 4); 365 id = inl(port); 366 if (id == 0 || id == 0xffffffff) 367 continue; 368 369 port = pci_cfgenable(0, device, 0, 8, 4); 370 class = inl(port) >> 8; 371 if (bootverbose) 372 printf("[class=%06x] ", class); 373 if (class == 0 || (class & 0xf870ff) != 0) 374 continue; 375 376 port = pci_cfgenable(0, device, 0, 14, 1); 377 header = inb(port); 378 if (bootverbose) 379 printf("[hdr=%02x] ", header); 380 if ((header & 0x7e) != 0) 381 continue; 382 383 if (bootverbose) 384 printf("is there (id=%08x)\n", id); 385 386 pci_cfgdisable(); 387 return (1); 388 } 389 if (bootverbose) 390 printf("-- nothing found\n"); 391 392 pci_cfgdisable(); 393 return (0); 394 } 395 396 static int 397 pcireg_cfgopen(void) 398 { 399 uint32_t mode1res, oldval1; 400 uint8_t mode2res, oldval2; 401 402 oldval1 = inl(CONF1_ADDR_PORT); 403 404 if (bootverbose) { 405 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n", 406 oldval1); 407 } 408 409 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 410 411 cfgmech = CFGMECH_1; 412 devmax = 32; 413 414 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 415 DELAY(1); 416 mode1res = inl(CONF1_ADDR_PORT); 417 outl(CONF1_ADDR_PORT, oldval1); 418 419 if (bootverbose) 420 printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 421 mode1res, CONF1_ENABLE_CHK); 422 423 if (mode1res) { 424 if (pci_cfgcheck(32)) 425 return (cfgmech); 426 } 427 428 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 429 mode1res = inl(CONF1_ADDR_PORT); 430 outl(CONF1_ADDR_PORT, oldval1); 431 432 if (bootverbose) 433 printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 434 mode1res, CONF1_ENABLE_CHK1); 435 436 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 437 if (pci_cfgcheck(32)) 438 return (cfgmech); 439 } 440 } 441 442 oldval2 = inb(CONF2_ENABLE_PORT); 443 444 if (bootverbose) { 445 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 446 oldval2); 447 } 448 449 if ((oldval2 & 0xf0) == 0) { 450 451 cfgmech = CFGMECH_2; 452 devmax = 16; 453 454 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 455 mode2res = inb(CONF2_ENABLE_PORT); 456 outb(CONF2_ENABLE_PORT, oldval2); 457 458 if (bootverbose) 459 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 460 mode2res, CONF2_ENABLE_CHK); 461 462 if (mode2res == CONF2_ENABLE_RES) { 463 if (bootverbose) 464 printf("pci_open(2a):\tnow trying mechanism 2\n"); 465 466 if (pci_cfgcheck(16)) 467 return (cfgmech); 468 } 469 } 470 471 cfgmech = CFGMECH_NONE; 472 devmax = 0; 473 return (cfgmech); 474 } 475 476 static int 477 pciereg_cfgopen(void) 478 { 479 struct pcie_cfg_list *pcielist; 480 struct pcie_cfg_elem *pcie_array, *elem; 481 #ifdef SMP 482 struct pcpu *pc; 483 #endif 484 vm_offset_t va; 485 int i; 486 487 if (bootverbose) 488 printf("Setting up PCIe mappings for BAR 0x%x\n", pciebar); 489 490 #ifdef SMP 491 SLIST_FOREACH(pc, &cpuhead, pc_allcpu) 492 #endif 493 { 494 495 pcie_array = malloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE, 496 M_DEVBUF, M_NOWAIT); 497 if (pcie_array == NULL) 498 return (0); 499 500 va = kmem_alloc_nofault(kernel_map, PCIE_CACHE * PAGE_SIZE); 501 if (va == 0) { 502 free(pcie_array, M_DEVBUF); 503 return (0); 504 } 505 506 #ifdef SMP 507 pcielist = &pcie_list[pc->pc_cpuid]; 508 #else 509 pcielist = &pcie_list[0]; 510 #endif 511 TAILQ_INIT(pcielist); 512 for (i = 0; i < PCIE_CACHE; i++) { 513 elem = &pcie_array[i]; 514 elem->vapage = va + (i * PAGE_SIZE); 515 elem->papage = 0; 516 TAILQ_INSERT_HEAD(pcielist, elem, elem); 517 } 518 } 519 520 521 cfgmech = CFGMECH_PCIE; 522 devmax = 32; 523 return (1); 524 } 525 526 #define PCIE_PADDR(bar, reg, bus, slot, func) \ 527 ((bar) | \ 528 (((bus) & 0xff) << 20) | \ 529 (((slot) & 0x1f) << 15) | \ 530 (((func) & 0x7) << 12) | \ 531 ((reg) & 0xfff)) 532 533 /* 534 * Find an element in the cache that matches the physical page desired, or 535 * create a new mapping from the least recently used element. 536 * A very simple LRU algorithm is used here, does it need to be more 537 * efficient? 538 */ 539 static __inline struct pcie_cfg_elem * 540 pciereg_findelem(vm_paddr_t papage) 541 { 542 struct pcie_cfg_list *pcielist; 543 struct pcie_cfg_elem *elem; 544 545 pcielist = &pcie_list[PCPU_GET(cpuid)]; 546 TAILQ_FOREACH(elem, pcielist, elem) { 547 if (elem->papage == papage) 548 break; 549 } 550 551 if (elem == NULL) { 552 elem = TAILQ_LAST(pcielist, pcie_cfg_list); 553 if (elem->papage != 0) { 554 pmap_kremove(elem->vapage); 555 invlpg(elem->vapage); 556 } 557 pmap_kenter(elem->vapage, papage); 558 elem->papage = papage; 559 } 560 561 if (elem != TAILQ_FIRST(pcielist)) { 562 TAILQ_REMOVE(pcielist, elem, elem); 563 TAILQ_INSERT_HEAD(pcielist, elem, elem); 564 } 565 return (elem); 566 } 567 568 static int 569 pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) 570 { 571 struct pcie_cfg_elem *elem; 572 volatile vm_offset_t va; 573 vm_paddr_t pa, papage; 574 int data; 575 576 critical_enter(); 577 pa = PCIE_PADDR(pciebar, reg, bus, slot, func); 578 papage = pa & ~PAGE_MASK; 579 elem = pciereg_findelem(papage); 580 va = elem->vapage | (pa & PAGE_MASK); 581 582 switch (bytes) { 583 case 4: 584 data = *(volatile uint32_t *)(va); 585 break; 586 case 2: 587 data = *(volatile uint16_t *)(va); 588 break; 589 case 1: 590 data = *(volatile uint8_t *)(va); 591 break; 592 default: 593 panic("pciereg_cfgread: invalid width"); 594 } 595 596 critical_exit(); 597 return (data); 598 } 599 600 static void 601 pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 602 { 603 struct pcie_cfg_elem *elem; 604 volatile vm_offset_t va; 605 vm_paddr_t pa, papage; 606 607 critical_enter(); 608 pa = PCIE_PADDR(pciebar, reg, bus, slot, func); 609 papage = pa & ~PAGE_MASK; 610 elem = pciereg_findelem(papage); 611 va = elem->vapage | (pa & PAGE_MASK); 612 613 switch (bytes) { 614 case 4: 615 *(volatile uint32_t *)(va) = data; 616 break; 617 case 2: 618 *(volatile uint16_t *)(va) = data; 619 break; 620 case 1: 621 *(volatile uint8_t *)(va) = data; 622 break; 623 default: 624 panic("pciereg_cfgwrite: invalid width"); 625 } 626 627 critical_exit(); 628 } 629