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, 0x0, 2); 164 did = pci_cfgregread(0, 0, 0, 0x2, 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 outl(CONF1_ADDR_PORT, 0); 284 break; 285 case CFGMECH_2: 286 outb(CONF2_ENABLE_PORT, 0); 287 outb(CONF2_FORWARD_PORT, 0); 288 break; 289 } 290 } 291 292 static int 293 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 294 { 295 int data = -1; 296 int port; 297 298 if (cfgmech == CFGMECH_PCIE) { 299 data = pciereg_cfgread(bus, slot, func, reg, bytes); 300 return (data); 301 } 302 303 mtx_lock_spin(&pcicfg_mtx); 304 port = pci_cfgenable(bus, slot, func, reg, bytes); 305 if (port != 0) { 306 switch (bytes) { 307 case 1: 308 data = inb(port); 309 break; 310 case 2: 311 data = inw(port); 312 break; 313 case 4: 314 data = inl(port); 315 break; 316 } 317 pci_cfgdisable(); 318 } 319 mtx_unlock_spin(&pcicfg_mtx); 320 return (data); 321 } 322 323 static void 324 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 325 { 326 int port; 327 328 if (cfgmech == CFGMECH_PCIE) { 329 pciereg_cfgwrite(bus, slot, func, reg, data, bytes); 330 return; 331 } 332 333 mtx_lock_spin(&pcicfg_mtx); 334 port = pci_cfgenable(bus, slot, func, reg, bytes); 335 if (port != 0) { 336 switch (bytes) { 337 case 1: 338 outb(port, data); 339 break; 340 case 2: 341 outw(port, data); 342 break; 343 case 4: 344 outl(port, data); 345 break; 346 } 347 pci_cfgdisable(); 348 } 349 mtx_unlock_spin(&pcicfg_mtx); 350 } 351 352 /* check whether the configuration mechanism has been correctly identified */ 353 static int 354 pci_cfgcheck(int maxdev) 355 { 356 uint32_t id, class; 357 uint8_t header; 358 uint8_t device; 359 int port; 360 361 if (bootverbose) 362 printf("pci_cfgcheck:\tdevice "); 363 364 for (device = 0; device < maxdev; device++) { 365 if (bootverbose) 366 printf("%d ", device); 367 368 port = pci_cfgenable(0, device, 0, 0, 4); 369 id = inl(port); 370 if (id == 0 || id == 0xffffffff) 371 continue; 372 373 port = pci_cfgenable(0, device, 0, 8, 4); 374 class = inl(port) >> 8; 375 if (bootverbose) 376 printf("[class=%06x] ", class); 377 if (class == 0 || (class & 0xf870ff) != 0) 378 continue; 379 380 port = pci_cfgenable(0, device, 0, 14, 1); 381 header = inb(port); 382 if (bootverbose) 383 printf("[hdr=%02x] ", header); 384 if ((header & 0x7e) != 0) 385 continue; 386 387 if (bootverbose) 388 printf("is there (id=%08x)\n", id); 389 390 pci_cfgdisable(); 391 return (1); 392 } 393 if (bootverbose) 394 printf("-- nothing found\n"); 395 396 pci_cfgdisable(); 397 return (0); 398 } 399 400 static int 401 pcireg_cfgopen(void) 402 { 403 uint32_t mode1res, oldval1; 404 uint8_t mode2res, oldval2; 405 406 oldval1 = inl(CONF1_ADDR_PORT); 407 408 if (bootverbose) { 409 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n", 410 oldval1); 411 } 412 413 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 414 415 cfgmech = CFGMECH_1; 416 devmax = 32; 417 418 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 419 DELAY(1); 420 mode1res = inl(CONF1_ADDR_PORT); 421 outl(CONF1_ADDR_PORT, oldval1); 422 423 if (bootverbose) 424 printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 425 mode1res, CONF1_ENABLE_CHK); 426 427 if (mode1res) { 428 if (pci_cfgcheck(32)) 429 return (cfgmech); 430 } 431 432 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 433 mode1res = inl(CONF1_ADDR_PORT); 434 outl(CONF1_ADDR_PORT, oldval1); 435 436 if (bootverbose) 437 printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 438 mode1res, CONF1_ENABLE_CHK1); 439 440 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 441 if (pci_cfgcheck(32)) 442 return (cfgmech); 443 } 444 } 445 446 oldval2 = inb(CONF2_ENABLE_PORT); 447 448 if (bootverbose) { 449 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 450 oldval2); 451 } 452 453 if ((oldval2 & 0xf0) == 0) { 454 455 cfgmech = CFGMECH_2; 456 devmax = 16; 457 458 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 459 mode2res = inb(CONF2_ENABLE_PORT); 460 outb(CONF2_ENABLE_PORT, oldval2); 461 462 if (bootverbose) 463 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 464 mode2res, CONF2_ENABLE_CHK); 465 466 if (mode2res == CONF2_ENABLE_RES) { 467 if (bootverbose) 468 printf("pci_open(2a):\tnow trying mechanism 2\n"); 469 470 if (pci_cfgcheck(16)) 471 return (cfgmech); 472 } 473 } 474 475 cfgmech = CFGMECH_NONE; 476 devmax = 0; 477 return (cfgmech); 478 } 479 480 static int 481 pciereg_cfgopen(void) 482 { 483 struct pcie_cfg_list *pcielist; 484 struct pcie_cfg_elem *pcie_array, *elem; 485 #ifdef SMP 486 struct pcpu *pc; 487 #endif 488 vm_offset_t va; 489 int i; 490 491 if (bootverbose) 492 printf("Setting up PCIe mappings for BAR 0x%x\n", pciebar); 493 494 #ifdef SMP 495 SLIST_FOREACH(pc, &cpuhead, pc_allcpu) 496 #endif 497 { 498 499 pcie_array = malloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE, 500 M_DEVBUF, M_NOWAIT); 501 if (pcie_array == NULL) 502 return (0); 503 504 va = kmem_alloc_nofault(kernel_map, PCIE_CACHE * PAGE_SIZE); 505 if (va == 0) { 506 free(pcie_array, M_DEVBUF); 507 return (0); 508 } 509 510 #ifdef SMP 511 pcielist = &pcie_list[pc->pc_cpuid]; 512 #else 513 pcielist = &pcie_list[0]; 514 #endif 515 TAILQ_INIT(pcielist); 516 for (i = 0; i < PCIE_CACHE; i++) { 517 elem = &pcie_array[i]; 518 elem->vapage = va + (i * PAGE_SIZE); 519 elem->papage = 0; 520 TAILQ_INSERT_HEAD(pcielist, elem, elem); 521 } 522 } 523 524 525 cfgmech = CFGMECH_PCIE; 526 devmax = 32; 527 return (1); 528 } 529 530 #define PCIE_PADDR(bar, reg, bus, slot, func) \ 531 ((bar) | \ 532 (((bus) & 0xff) << 20) | \ 533 (((slot) & 0x1f) << 15) | \ 534 (((func) & 0x7) << 12) | \ 535 ((reg) & 0xfff)) 536 537 /* 538 * Find an element in the cache that matches the physical page desired, or 539 * create a new mapping from the least recently used element. 540 * A very simple LRU algorithm is used here, does it need to be more 541 * efficient? 542 */ 543 static __inline struct pcie_cfg_elem * 544 pciereg_findelem(vm_paddr_t papage) 545 { 546 struct pcie_cfg_list *pcielist; 547 struct pcie_cfg_elem *elem; 548 549 pcielist = &pcie_list[PCPU_GET(cpuid)]; 550 TAILQ_FOREACH(elem, pcielist, elem) { 551 if (elem->papage == papage) 552 break; 553 } 554 555 if (elem == NULL) { 556 elem = TAILQ_LAST(pcielist, pcie_cfg_list); 557 if (elem->papage != 0) { 558 pmap_kremove(elem->vapage); 559 invlpg(elem->vapage); 560 } 561 pmap_kenter(elem->vapage, papage); 562 elem->papage = papage; 563 } 564 565 if (elem != TAILQ_FIRST(pcielist)) { 566 TAILQ_REMOVE(pcielist, elem, elem); 567 TAILQ_INSERT_HEAD(pcielist, elem, elem); 568 } 569 return (elem); 570 } 571 572 static int 573 pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) 574 { 575 struct pcie_cfg_elem *elem; 576 volatile vm_offset_t va; 577 vm_paddr_t pa, papage; 578 int data; 579 580 critical_enter(); 581 pa = PCIE_PADDR(pciebar, reg, bus, slot, func); 582 papage = pa & ~PAGE_MASK; 583 elem = pciereg_findelem(papage); 584 va = elem->vapage | (pa & PAGE_MASK); 585 586 switch (bytes) { 587 case 4: 588 data = *(volatile uint32_t *)(va); 589 break; 590 case 2: 591 data = *(volatile uint16_t *)(va); 592 break; 593 case 1: 594 data = *(volatile uint8_t *)(va); 595 break; 596 default: 597 panic("pciereg_cfgread: invalid width"); 598 } 599 600 critical_exit(); 601 return (data); 602 } 603 604 static void 605 pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 606 { 607 struct pcie_cfg_elem *elem; 608 volatile vm_offset_t va; 609 vm_paddr_t pa, papage; 610 611 critical_enter(); 612 pa = PCIE_PADDR(pciebar, reg, bus, slot, func); 613 papage = pa & ~PAGE_MASK; 614 elem = pciereg_findelem(papage); 615 va = elem->vapage | (pa & PAGE_MASK); 616 617 switch (bytes) { 618 case 4: 619 *(volatile uint32_t *)(va) = data; 620 break; 621 case 2: 622 *(volatile uint16_t *)(va) = data; 623 break; 624 case 1: 625 *(volatile uint8_t *)(va) = data; 626 break; 627 default: 628 panic("pciereg_cfgwrite: invalid width"); 629 } 630 631 critical_exit(); 632 } 633