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