1 /* $NetBSD: pcibios.c,v 1.34 2007/03/04 05:59:59 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1999, by UCHIYAMA Yasushi 42 * All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. The name of the developer may NOT be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65 /* 66 * Interface to the PCI BIOS and PCI Interrupt Routing table. 67 */ 68 69 #include <sys/cdefs.h> 70 __KERNEL_RCSID(0, "$NetBSD: pcibios.c,v 1.34 2007/03/04 05:59:59 christos Exp $"); 71 72 #include "opt_pcibios.h" 73 #include "opt_pcifixup.h" 74 75 #include <sys/param.h> 76 #include <sys/systm.h> 77 #include <sys/device.h> 78 #include <sys/malloc.h> 79 80 #include <dev/isa/isareg.h> 81 #include <machine/isa_machdep.h> 82 83 #include <dev/pci/pcireg.h> 84 #include <dev/pci/pcivar.h> 85 #include <dev/pci/pcidevs.h> 86 87 #include <i386/pci/pcibios.h> 88 89 #if defined(PCIBIOS_INTR_FIXUP) || defined(PCIBIOS_ADDR_FIXUP) || \ 90 defined(PCIBIOS_BUS_FIXUP) 91 #error The options PCIBIOS_INTR_FIXUP, PCIBIOS_ADDR_FIXUP, and PCIBIOS_BUS_FIXUP have been obsoleted by PCI_INTR_FIXUP, PCI_ADDR_FIXUP, and PCI_BUS_FIXUP. Please adjust your kernel configuration file. 92 #endif 93 94 #ifdef PCI_INTR_FIXUP 95 #include <i386/pci/pci_intr_fixup.h> 96 #endif 97 98 #include <machine/bios32.h> 99 100 #ifdef PCIBIOSVERBOSE 101 int pcibiosverbose = 1; 102 #endif 103 104 int pcibios_present; 105 106 struct pcibios_pir_header pcibios_pir_header; 107 struct pcibios_intr_routing *pcibios_pir_table; 108 int pcibios_pir_table_nentries; 109 int pcibios_max_bus; 110 111 struct bios32_entry pcibios_entry; 112 113 void pcibios_pir_init(void); 114 115 int pcibios_get_status(uint32_t *, uint32_t *, uint32_t *, 116 uint32_t *, uint32_t *, uint32_t *, uint32_t *); 117 int pcibios_get_intr_routing(struct pcibios_intr_routing *, 118 int *, uint16_t *); 119 120 int pcibios_return_code(uint16_t, const char *); 121 122 void pcibios_print_exclirq(void); 123 124 #ifdef PCIBIOS_LIBRETTO_FIXUP 125 /* for Libretto L2/L3 hack */ 126 static void pcibios_fixup_pir_table(void); 127 static void pcibios_fixup_pir_table_mask(struct pcibios_linkmap *); 128 129 struct pcibios_linkmap pir_mask[] = { 130 { 2, 0x0040 }, 131 { 7, 0x0080 }, 132 { 8, 0x0020 }, 133 { 0, 0x0000 } 134 }; 135 #endif 136 137 #ifdef PCIBIOS_SHARP_MM20_FIXUP 138 static void pcibios_mm20_fixup(void); 139 #endif 140 141 #ifdef PCIINTR_DEBUG 142 void pcibios_print_pir_table(void); 143 #endif 144 145 #define PCI_IRQ_TABLE_START 0xf0000 146 #define PCI_IRQ_TABLE_END 0xfffff 147 148 void 149 pcibios_init(void) 150 { 151 struct bios32_entry_info ei; 152 uint32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2; 153 154 if (bios32_service(BIOS32_MAKESIG('$', 'P', 'C', 'I'), 155 &pcibios_entry, &ei) == 0) { 156 /* 157 * No PCI BIOS found; will fall back on old 158 * mechanism. 159 */ 160 return; 161 } 162 163 /* 164 * We've located the PCI BIOS service; get some information 165 * about it. 166 */ 167 if (pcibios_get_status(&rev_maj, &rev_min, &mech1, &mech2, 168 &scmech1, &scmech2, &pcibios_max_bus) != PCIBIOS_SUCCESS) { 169 /* 170 * We can't use the PCI BIOS; will fall back on old 171 * mechanism. 172 */ 173 return; 174 } 175 176 aprint_normal("PCI BIOS rev. %d.%d found at 0x%lx\n", 177 rev_maj, rev_min >> 4, ei.bei_entry); 178 aprint_verbose("pcibios: config mechanism %s%s, special cycles %s%s, " 179 "last bus %d\n", 180 mech1 ? "[1]" : "[x]", 181 mech2 ? "[2]" : "[x]", 182 scmech1 ? "[1]" : "[x]", 183 scmech2 ? "[2]" : "[x]", 184 pcibios_max_bus); 185 186 /* 187 * The PCI BIOS tells us the config mechanism; fill it in now 188 * so that pci_mode_detect() doesn't have to look for it. 189 */ 190 pci_mode = mech1 ? 1 : 2; 191 192 pcibios_present = 1; 193 194 /* 195 * Find the PCI IRQ Routing table. 196 */ 197 pcibios_pir_init(); 198 199 #ifdef PCI_INTR_FIXUP 200 if (pcibios_pir_table != NULL) { 201 int rv; 202 uint16_t pciirq; 203 204 /* 205 * Fixup interrupt routing. 206 */ 207 rv = pci_intr_fixup(NULL, X86_BUS_SPACE_IO, &pciirq); 208 switch (rv) { 209 case -1: 210 /* Non-fatal error. */ 211 aprint_error("Warning: unable to fix up PCI interrupt " 212 "routing\n"); 213 break; 214 215 case 1: 216 /* Fatal error. */ 217 panic("pcibios_init: interrupt fixup failed"); 218 break; 219 } 220 221 /* 222 * XXX Clear `pciirq' from the ISA interrupt allocation 223 * XXX mask. 224 */ 225 } 226 #endif 227 } 228 229 void 230 pcibios_pir_init(void) 231 { 232 char *devinfo; 233 paddr_t pa; 234 char *p; 235 unsigned char cksum; 236 uint16_t tablesize; 237 uint8_t rev_maj, rev_min; 238 int i; 239 240 for (pa = PCI_IRQ_TABLE_START; pa < PCI_IRQ_TABLE_END; pa += 16) { 241 p = (void *)ISA_HOLE_VADDR(pa); 242 if (*(int *)p != BIOS32_MAKESIG('$', 'P', 'I', 'R')) { 243 /* 244 * XXX: Some laptops (Toshiba/Libretto L series) 245 * use _PIR instead of $PIR. So we try that too. 246 */ 247 if (*(int *)p != BIOS32_MAKESIG('_', 'P', 'I', 'R')) 248 continue; 249 } 250 251 rev_min = *(p + 4); 252 rev_maj = *(p + 5); 253 tablesize = *(uint16_t *)(p + 6); 254 255 cksum = 0; 256 for (i = 0; i < tablesize; i++) 257 cksum += *(unsigned char *)(p + i); 258 259 aprint_normal( 260 "PCI IRQ Routing Table rev. %d.%d found at 0x%lx, " 261 "size %d bytes (%d entries)\n", rev_maj, rev_min, pa, 262 tablesize, (tablesize - 32) / 16); 263 264 if (cksum != 0) { 265 aprint_error("pcibios_pir_init: bad IRQ table checksum\n"); 266 continue; 267 } 268 269 if (tablesize < 32 || (tablesize % 16) != 0) { 270 aprint_error("pcibios_pir_init: bad IRQ table size\n"); 271 continue; 272 } 273 274 if (rev_maj != 1 || rev_min != 0) { 275 aprint_error("pcibios_pir_init: unsupported IRQ table " 276 "version\n"); 277 continue; 278 } 279 280 /* 281 * We can handle this table! Make a copy of it. 282 */ 283 memcpy(&pcibios_pir_header, p, 32); 284 pcibios_pir_table = malloc(tablesize - 32, M_DEVBUF, 285 M_NOWAIT); 286 if (pcibios_pir_table == NULL) { 287 aprint_error("pcibios_pir_init: no memory for $PIR\n"); 288 return; 289 } 290 memcpy(pcibios_pir_table, p + 32, tablesize - 32); 291 pcibios_pir_table_nentries = (tablesize - 32) / 16; 292 293 aprint_verbose("PCI Interrupt Router at %03d:%02d:%01d", 294 pcibios_pir_header.router_bus, 295 PIR_DEVFUNC_DEVICE(pcibios_pir_header.router_devfunc), 296 PIR_DEVFUNC_FUNCTION(pcibios_pir_header.router_devfunc)); 297 if (pcibios_pir_header.compat_router != 0) { 298 devinfo = malloc(256, M_DEVBUF, M_NOWAIT); 299 if (devinfo) { 300 pci_devinfo(pcibios_pir_header.compat_router, 301 0, 0, devinfo, 256); 302 aprint_verbose(" (%s compatible)", devinfo); 303 free(devinfo, M_DEVBUF); 304 } 305 } 306 aprint_verbose("\n"); 307 pcibios_print_exclirq(); 308 309 #ifdef PCIBIOS_LIBRETTO_FIXUP 310 /* for Libretto L2/L3 hack */ 311 pcibios_fixup_pir_table(); 312 #endif 313 #ifdef PCIBIOS_SHARP_MM20_FIXUP 314 pcibios_mm20_fixup(); 315 #endif 316 #ifdef PCIINTR_DEBUG 317 pcibios_print_pir_table(); 318 #endif 319 return; 320 } 321 322 /* 323 * If there was no PIR table found, try using the PCI BIOS 324 * Get Interrupt Routing call. 325 * 326 * XXX The interface to this call sucks; just allocate enough 327 * XXX room for 32 entries. 328 */ 329 pcibios_pir_table_nentries = 32; 330 pcibios_pir_table = malloc(pcibios_pir_table_nentries * 331 sizeof(*pcibios_pir_table), M_DEVBUF, M_NOWAIT); 332 if (pcibios_pir_table == NULL) { 333 aprint_error("pcibios_pir_init: no memory for $PIR\n"); 334 return; 335 } 336 if (pcibios_get_intr_routing(pcibios_pir_table, 337 &pcibios_pir_table_nentries, 338 &pcibios_pir_header.exclusive_irq) != PCIBIOS_SUCCESS) { 339 aprint_normal("No PCI IRQ Routing information available.\n"); 340 free(pcibios_pir_table, M_DEVBUF); 341 pcibios_pir_table = NULL; 342 pcibios_pir_table_nentries = 0; 343 return; 344 } 345 aprint_verbose("PCI BIOS has %d Interrupt Routing table entries\n", 346 pcibios_pir_table_nentries); 347 pcibios_print_exclirq(); 348 349 #ifdef PCIBIOS_LIBRETTO_FIXUP 350 /* for Libretto L2/L3 hack */ 351 pcibios_fixup_pir_table(); 352 #endif 353 #ifdef PCIBIOS_SHARP_MM20_FIXUP 354 pcibios_mm20_fixup(); 355 #endif 356 #ifdef PCIINTR_DEBUG 357 pcibios_print_pir_table(); 358 #endif 359 } 360 361 int 362 pcibios_get_status(uint32_t *rev_maj, uint32_t *rev_min, 363 uint32_t *mech1, uint32_t *mech2, uint32_t *scmech1, uint32_t *scmech2, 364 uint32_t *maxbus) 365 { 366 uint16_t ax, bx, cx; 367 uint32_t edx; 368 int rv; 369 370 __asm volatile("lcall *(%%edi) ; \ 371 jc 1f ; \ 372 xor %%ah, %%ah ; \ 373 1:" 374 : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (edx) 375 : "0" (0xb101), "D" (&pcibios_entry)); 376 377 rv = pcibios_return_code(ax, "pcibios_get_status"); 378 if (rv != PCIBIOS_SUCCESS) 379 return (rv); 380 381 if (edx != BIOS32_MAKESIG('P', 'C', 'I', ' ')) 382 return (PCIBIOS_SERVICE_NOT_PRESENT); /* XXX */ 383 384 /* 385 * Fill in the various pieces if info we're looking for. 386 */ 387 *mech1 = ax & 1; 388 *mech2 = ax & (1 << 1); 389 *scmech1 = ax & (1 << 4); 390 *scmech2 = ax & (1 << 5); 391 *rev_maj = (bx >> 8) & 0xff; 392 *rev_min = bx & 0xff; 393 *maxbus = cx & 0xff; 394 395 return (PCIBIOS_SUCCESS); 396 } 397 398 int 399 pcibios_get_intr_routing(struct pcibios_intr_routing *table, 400 int *nentries, uint16_t *exclirq) 401 { 402 uint16_t ax, bx; 403 int rv; 404 struct { 405 uint16_t size; 406 void *offset; 407 uint16_t segment; 408 } __attribute__((__packed__)) args; 409 410 args.size = *nentries * sizeof(*table); 411 args.offset = (void *)table; 412 args.segment = GSEL(GDATA_SEL, SEL_KPL); 413 414 memset(table, 0, args.size); 415 416 __asm volatile("lcall *(%%esi) ; \ 417 jc 1f ; \ 418 xor %%ah, %%ah ; \ 419 1: movw %w2, %%ds ; \ 420 movw %w2, %%es" 421 : "=a" (ax), "=b" (bx) 422 : "r" GSEL(GDATA_SEL, SEL_KPL), "0" (0xb10e), "1" (0), 423 "D" (&args), "S" (&pcibios_entry)); 424 425 rv = pcibios_return_code(ax, "pcibios_get_intr_routing"); 426 if (rv != PCIBIOS_SUCCESS) 427 return (rv); 428 429 *nentries = args.size / sizeof(*table); 430 *exclirq = bx; 431 432 return (PCIBIOS_SUCCESS); 433 } 434 435 int 436 pcibios_return_code(uint16_t ax, const char *func) 437 { 438 const char *errstr; 439 int rv = ax >> 8; 440 441 switch (rv) { 442 case PCIBIOS_SUCCESS: 443 return (PCIBIOS_SUCCESS); 444 445 case PCIBIOS_SERVICE_NOT_PRESENT: 446 errstr = "service not present"; 447 break; 448 449 case PCIBIOS_FUNCTION_NOT_SUPPORTED: 450 errstr = "function not supported"; 451 break; 452 453 case PCIBIOS_BAD_VENDOR_ID: 454 errstr = "bad vendor ID"; 455 break; 456 457 case PCIBIOS_DEVICE_NOT_FOUND: 458 errstr = "device not found"; 459 break; 460 461 case PCIBIOS_BAD_REGISTER_NUMBER: 462 errstr = "bad register number"; 463 break; 464 465 case PCIBIOS_SET_FAILED: 466 errstr = "set failed"; 467 break; 468 469 case PCIBIOS_BUFFER_TOO_SMALL: 470 errstr = "buffer too small"; 471 break; 472 473 default: 474 aprint_error("%s: unknown return code 0x%x\n", func, rv); 475 return (rv); 476 } 477 478 aprint_error("%s: %s\n", func, errstr); 479 return (rv); 480 } 481 482 void 483 pcibios_print_exclirq(void) 484 { 485 int i; 486 487 if (pcibios_pir_header.exclusive_irq) { 488 aprint_verbose("PCI Exclusive IRQs:"); 489 for (i = 0; i < 16; i++) { 490 if (pcibios_pir_header.exclusive_irq & (1 << i)) 491 aprint_verbose(" %d", i); 492 } 493 aprint_verbose("\n"); 494 } 495 } 496 497 #ifdef PCIBIOS_LIBRETTO_FIXUP 498 /* for Libretto L2/L3 hack */ 499 static void 500 pcibios_fixup_pir_table(void) 501 { 502 struct pcibios_linkmap *m; 503 504 for (m = pir_mask; m->link != 0; m++) 505 pcibios_fixup_pir_table_mask(m); 506 } 507 508 void 509 pcibios_fixup_pir_table_mask(struct pcibios_linkmap *mask) 510 { 511 int i, j; 512 513 for (i = 0; i < pcibios_pir_table_nentries; i++) { 514 for (j = 0; j < 4; j++) { 515 if (pcibios_pir_table[i].linkmap[j].link == mask->link) { 516 pcibios_pir_table[i].linkmap[j].bitmap 517 &= mask->bitmap; 518 } 519 } 520 } 521 } 522 #endif 523 524 #ifdef PCIINTR_DEBUG 525 void 526 pcibios_print_pir_table(void) 527 { 528 int i, j; 529 530 for (i = 0; i < pcibios_pir_table_nentries; i++) { 531 printf("PIR Entry %d:\n", i); 532 printf("\tBus: %d Device: %d\n", 533 pcibios_pir_table[i].bus, 534 PIR_DEVFUNC_DEVICE(pcibios_pir_table[i].device)); 535 for (j = 0; j < 4; j++) { 536 printf("\t\tINT%c: link 0x%02x bitmap 0x%04x\n", 537 'A' + j, 538 pcibios_pir_table[i].linkmap[j].link, 539 pcibios_pir_table[i].linkmap[j].bitmap); 540 } 541 } 542 } 543 #endif 544 545 #ifdef PCIBIOS_SHARP_MM20_FIXUP 546 /* 547 * This is a gross hack to get the interrupt from the EHCI controller 548 * working on a Sharp MM20. The BIOS is just incredibly buggy. 549 * 550 * The story thus far: 551 * The modern way to route the interrupt is to use ACPI. But using 552 * ACPI fails with an error message about an uninitialized local 553 * variable in the AML code. (It works in Windows, but fails in NetBSD 554 * and Linux.) 555 * 556 * The second attempt is to use PCI Interrupt Routing table. But this 557 * fails because the table does not contain any information about the 558 * interrupt from the EHCI controller. This is probably due to the fact 559 * that the table is compatible with ALi M1543, but the MM20 has an ALi M1563. 560 * The M1563 has additional interrupt lines. The ali1543.c code also 561 * cannot handle the M1653's extended interrupts. And fixing this is 562 * difficult since getting a data sheet from ALi requires signing an NDA. 563 * 564 * The third attempt is to use a BIOS call to route the interrupt 565 * (as FreeBSD does) with manually generated information. But the BIOS call 566 * fails because the BIOS code is not quite position independent. It makes 567 * some assumption about where the code segment register points. 568 * 569 * So the solution is to use the third attempt, but with a patched version 570 * of the BIOS. 571 * -- lennart@augustsson.net 572 */ 573 574 #define BIOS32_START 0xe0000 575 #define BIOS32_SIZE 0x20000 576 577 static char pcibios_shadow[BIOS32_SIZE]; 578 static struct bios32_entry pcibios_entry_shadow; 579 580 /* 581 * Copy BIOS and zap offending instruction. 582 * The bad instruction is 583 * mov %cs:0x63c(%ebx),%ah 584 * NetBSD does not have the code segment set up for this to work. 585 * Using the value 0xff for the table entry seems to work. 586 * The replacement is 587 * mov $0xff,%ah; nop; nop; nop; nop; nop 588 */ 589 static void 590 pcibios_copy_bios(void) 591 { 592 uint8_t *bad_instr; 593 594 memcpy(pcibios_shadow, ISA_HOLE_VADDR(BIOS32_START), BIOS32_SIZE); 595 pcibios_entry_shadow = pcibios_entry; 596 pcibios_entry_shadow.offset = 597 (void*)((u_long)pcibios_shadow + 598 (u_long)pcibios_entry.offset - 599 (u_long)ISA_HOLE_VADDR(BIOS32_START)); 600 601 bad_instr = (uint8_t *)pcibios_entry_shadow.offset + 0x499; 602 if (*bad_instr != 0x2e) 603 panic("bad bios"); 604 bad_instr[0] = 0xb4; bad_instr[1] = 0xff; /* mov $0xff,%ah */ 605 bad_instr[2] = 0x90; /* nop */ 606 bad_instr[3] = 0x90; /* nop */ 607 bad_instr[4] = 0x90; /* nop */ 608 bad_instr[5] = 0x90; /* nop */ 609 bad_instr[6] = 0x90; /* nop */ 610 } 611 612 /* 613 * Call BIOS to route an interrupt. 614 * The PCI device is identified by bus,device,func. 615 * The interrupt is on pin PIN (A-D) and interrupt IRQ. 616 * BIOS knows the magic for the interrupt controller. 617 */ 618 static int 619 pcibios_biosroute(int bus, int device, int func, int pin, int irq) 620 { 621 uint16_t ax, bx, cx; 622 int rv; 623 624 aprint_debug("pcibios_biosroute: b,d,f=%d,%d,%d pin=%x irq=%d\n", 625 bus, device, func, pin+0xa, irq); 626 627 bx = (bus << 8) | (device << 3) | func; 628 cx = (irq << 8) | (0xa + pin); 629 630 __asm volatile("lcall *(%%esi) ; \ 631 jc 1f ; \ 632 xor %%ah, %%ah ; \ 633 1: movw %w1, %%ds ; \ 634 movw %w1, %%es" 635 : "=a" (ax) 636 : "r" GSEL(GDATA_SEL, SEL_KPL), "0" (0xb10f), 637 "b" (bx), "c" (cx), 638 "S" (&pcibios_entry_shadow)); 639 640 rv = pcibios_return_code(ax, "pcibios_biosroute"); 641 642 return rv; 643 } 644 645 #define MM20_PCI_BUS 0 646 #define MM20_PCI_EHCI_DEV 15 647 #define MM20_PCI_EHCI_FUNC 3 648 #define MM20_PCI_EHCI_PIN 3 649 #define MM20_PCI_EHCI_INTR 11 650 #define MM20_PCI_ISA_DEV 3 651 #define MM20_PCI_ISA_FUNC 0 652 653 static void 654 pcibios_mm20_fixup(void) 655 { 656 pci_chipset_tag_t pc; 657 pcitag_t tag; 658 659 /* Copy BIOS */ 660 pcibios_copy_bios(); 661 /* Route the interrupt for the EHCI controller. */ 662 (void)pcibios_biosroute(MM20_PCI_BUS, 663 MM20_PCI_EHCI_DEV, 664 MM20_PCI_EHCI_FUNC, 665 MM20_PCI_EHCI_PIN, 666 MM20_PCI_EHCI_INTR); 667 668 /* Fake some tags. */ 669 pc = NULL; 670 tag = pci_make_tag(pc, MM20_PCI_BUS, MM20_PCI_EHCI_DEV, 671 MM20_PCI_EHCI_FUNC); 672 /* Set interrupt register in EHCI controller */ 673 pci_conf_write(pc, tag, PCI_INTERRUPT_REG, 674 0x50000400 + MM20_PCI_EHCI_INTR); 675 tag = pci_make_tag(pc, MM20_PCI_BUS, MM20_PCI_ISA_DEV, 676 MM20_PCI_ISA_FUNC); 677 /* Set some unknown registers in the ISA bridge. */ 678 pci_conf_write(pc, tag, 0x58, 0xd87f5300); 679 pci_conf_write(pc, tag, 0x74, 0x00000009); 680 } 681 682 #endif /* PCIBIOS_SHARP_MM20_FIXUP */ 683