1 /* $OpenBSD: pci_machdep.c,v 1.32 2009/09/28 15:58:30 kettenis Exp $ */ 2 /* $NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */ 3 4 /*- 5 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. 36 * Copyright (c) 1994 Charles M. Hannum. All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by Charles M. Hannum. 49 * 4. The name of the author 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 ``AS IS'' AND ANY EXPRESS OR 53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 /* 65 * Machine-specific functions for PCI autoconfiguration. 66 */ 67 68 #include <sys/types.h> 69 #include <sys/param.h> 70 #include <sys/time.h> 71 #include <sys/systm.h> 72 #include <sys/errno.h> 73 #include <sys/device.h> 74 #include <sys/extent.h> 75 #include <sys/malloc.h> 76 77 #include <uvm/uvm_extern.h> 78 79 #include <machine/bus.h> 80 81 #include <machine/pio.h> 82 #include <machine/intr.h> 83 #include <machine/biosvar.h> 84 85 #include <dev/isa/isareg.h> 86 #include <dev/isa/isavar.h> 87 #include <dev/pci/pcivar.h> 88 #include <dev/pci/pcireg.h> 89 #include <dev/pci/pcidevs.h> 90 #include <dev/pci/ppbreg.h> 91 92 #include "ioapic.h" 93 94 #if NIOAPIC > 0 95 #include <machine/i82093var.h> 96 #include <machine/mpbiosvar.h> 97 #endif 98 99 struct mutex pci_conf_lock = MUTEX_INITIALIZER(IPL_HIGH); 100 101 #define PCI_CONF_LOCK() \ 102 do { \ 103 mtx_enter(&pci_conf_lock); \ 104 } while (0) 105 106 #define PCI_CONF_UNLOCK() \ 107 do { \ 108 mtx_leave(&pci_conf_lock); \ 109 } while (0) 110 111 #define PCI_MODE1_ENABLE 0x80000000UL 112 #define PCI_MODE1_ADDRESS_REG 0x0cf8 113 #define PCI_MODE1_DATA_REG 0x0cfc 114 115 /* 116 * PCI doesn't have any special needs; just use the generic versions 117 * of these functions. 118 */ 119 struct bus_dma_tag pci_bus_dma_tag = { 120 NULL, /* _may_bounce */ 121 _bus_dmamap_create, 122 _bus_dmamap_destroy, 123 _bus_dmamap_load, 124 _bus_dmamap_load_mbuf, 125 _bus_dmamap_load_uio, 126 _bus_dmamap_load_raw, 127 _bus_dmamap_unload, 128 NULL, 129 _bus_dmamem_alloc, 130 _bus_dmamem_free, 131 _bus_dmamem_map, 132 _bus_dmamem_unmap, 133 _bus_dmamem_mmap, 134 }; 135 136 extern void amdgart_probe(struct pcibus_attach_args *); 137 138 void 139 pci_attach_hook(struct device *parent, struct device *self, 140 struct pcibus_attach_args *pba) 141 { 142 #ifndef SMALL_KERNEL 143 if (pba->pba_bus == 0) 144 amdgart_probe(pba); 145 #endif /* !SMALL_KERNEL */ 146 } 147 148 int 149 pci_bus_maxdevs(pci_chipset_tag_t pc, int busno) 150 { 151 return (32); 152 } 153 154 pcitag_t 155 pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function) 156 { 157 if (bus >= 256 || device >= 32 || function >= 8) 158 panic("pci_make_tag: bad request"); 159 160 return (PCI_MODE1_ENABLE | 161 (bus << 16) | (device << 11) | (function << 8)); 162 } 163 164 void 165 pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp) 166 { 167 if (bp != NULL) 168 *bp = (tag >> 16) & 0xff; 169 if (dp != NULL) 170 *dp = (tag >> 11) & 0x1f; 171 if (fp != NULL) 172 *fp = (tag >> 8) & 0x7; 173 } 174 175 pcireg_t 176 pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 177 { 178 pcireg_t data; 179 180 PCI_CONF_LOCK(); 181 outl(PCI_MODE1_ADDRESS_REG, tag | reg); 182 data = inl(PCI_MODE1_DATA_REG); 183 outl(PCI_MODE1_ADDRESS_REG, 0); 184 PCI_CONF_UNLOCK(); 185 186 return data; 187 } 188 189 void 190 pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) 191 { 192 PCI_CONF_LOCK(); 193 outl(PCI_MODE1_ADDRESS_REG, tag | reg); 194 outl(PCI_MODE1_DATA_REG, data); 195 outl(PCI_MODE1_ADDRESS_REG, 0); 196 PCI_CONF_UNLOCK(); 197 } 198 199 int 200 pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 201 { 202 int pin = pa->pa_rawintrpin; 203 int line = pa->pa_intrline; 204 #if NIOAPIC > 0 205 int bus, dev, func; 206 int mppin; 207 #endif 208 209 if (pin == 0) { 210 /* No IRQ used. */ 211 goto bad; 212 } 213 214 if (pin > PCI_INTERRUPT_PIN_MAX) { 215 printf("pci_intr_map: bad interrupt pin %d\n", pin); 216 goto bad; 217 } 218 219 ihp->tag = pa->pa_tag; 220 ihp->line = line; 221 ihp->pin = pin; 222 223 #if NIOAPIC > 0 224 pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &func); 225 if (mp_busses != NULL) { 226 mppin = (dev << 2)|(pin - 1); 227 if (intr_find_mpmapping(bus, mppin, &ihp->line) == 0) { 228 ihp->line |= line; 229 return 0; 230 } 231 if (pa->pa_bridgetag) { 232 int swizpin = PPB_INTERRUPT_SWIZZLE(pin, dev); 233 if (pa->pa_bridgeih[swizpin - 1].line != -1) { 234 ihp->line = pa->pa_bridgeih[swizpin - 1].line; 235 ihp->line |= line; 236 return 0; 237 } 238 } 239 /* 240 * No explicit PCI mapping found. This is not fatal, 241 * we'll try the ISA (or possibly EISA) mappings next. 242 */ 243 } 244 #endif 245 246 /* 247 * Section 6.2.4, `Miscellaneous Functions', says that 255 means 248 * `unknown' or `no connection' on a PC. We assume that a device with 249 * `no connection' either doesn't have an interrupt (in which case the 250 * pin number should be 0, and would have been noticed above), or 251 * wasn't configured by the BIOS (in which case we punt, since there's 252 * no real way we can know how the interrupt lines are mapped in the 253 * hardware). 254 * 255 * XXX 256 * Since IRQ 0 is only used by the clock, and we can't actually be sure 257 * that the BIOS did its job, we also recognize that as meaning that 258 * the BIOS has not configured the device. 259 */ 260 if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) 261 goto bad; 262 263 if (line >= NUM_LEGACY_IRQS) { 264 printf("pci_intr_map: bad interrupt line %d\n", line); 265 goto bad; 266 } 267 if (line == 2) { 268 printf("pci_intr_map: changed line 2 to line 9\n"); 269 line = 9; 270 } 271 272 #if NIOAPIC > 0 273 if (mp_busses != NULL) { 274 if (mp_isa_bus != NULL && 275 intr_find_mpmapping(mp_isa_bus->mb_idx, line, &ihp->line) == 0) { 276 ihp->line |= line; 277 return 0; 278 } 279 #if NEISA > 0 280 if (mp_eisa_bus != NULL && 281 intr_find_mpmapping(mp_eisa_bus->mb_idx, line, &ihp->line) == 0) { 282 ihp->line |= line; 283 return 0; 284 } 285 #endif 286 printf("pci_intr_map: bus %d dev %d func %d pin %d; line %d\n", 287 bus, dev, func, pin, line); 288 printf("pci_intr_map: no MP mapping found\n"); 289 } 290 #endif 291 292 return 0; 293 294 bad: 295 ihp->line = -1; 296 return 1; 297 } 298 299 const char * 300 pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih) 301 { 302 static char irqstr[64]; 303 304 if (ih.line == 0) 305 panic("pci_intr_string: bogus handle 0x%x", ih.line); 306 307 #if NIOAPIC > 0 308 if (ih.line & APIC_INT_VIA_APIC) 309 snprintf(irqstr, sizeof(irqstr), "apic %d int %d (irq %d)", 310 APIC_IRQ_APIC(ih.line), 311 APIC_IRQ_PIN(ih.line), 312 pci_intr_line(pc, ih)); 313 else 314 snprintf(irqstr, sizeof(irqstr), "irq %d", 315 pci_intr_line(pc, ih)); 316 #else 317 snprintf(irqstr, sizeof(irqstr), "irq %d", pci_intr_line(pc, ih)); 318 #endif 319 return (irqstr); 320 } 321 322 #include "acpiprt.h" 323 #if NACPIPRT > 0 324 void acpiprt_route_interrupt(int bus, int dev, int pin); 325 #endif 326 327 void * 328 pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level, 329 int (*func)(void *), void *arg, const char *what) 330 { 331 int pin, irq; 332 int bus, dev; 333 struct pic *pic; 334 335 pci_decompose_tag(pc, ih.tag, &bus, &dev, NULL); 336 #if NACPIPRT > 0 337 acpiprt_route_interrupt(bus, dev, ih.pin); 338 #endif 339 340 pic = &i8259_pic; 341 pin = irq = ih.line; 342 343 #if NIOAPIC > 0 344 if (ih.line & APIC_INT_VIA_APIC) { 345 pic = (struct pic *)ioapic_find(APIC_IRQ_APIC(ih.line)); 346 if (pic == NULL) { 347 printf("pci_intr_establish: bad ioapic %d\n", 348 APIC_IRQ_APIC(ih.line)); 349 return NULL; 350 } 351 pin = APIC_IRQ_PIN(ih.line); 352 irq = APIC_IRQ_LEGACY_IRQ(ih.line); 353 if (irq < 0 || irq >= NUM_LEGACY_IRQS) 354 irq = -1; 355 } 356 #endif 357 358 return intr_establish(irq, pic, pin, IST_LEVEL, level, func, arg, what); 359 } 360 361 void 362 pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie) 363 { 364 intr_disestablish(cookie); 365 } 366 367 struct extent *pciio_ex; 368 struct extent *pcimem_ex; 369 370 void 371 pci_init_extents(void) 372 { 373 bios_memmap_t *bmp; 374 u_int64_t size; 375 376 if (pciio_ex == NULL) { 377 /* 378 * We only have 64K of addressable I/O space. 379 * However, since BARs may contain garbage, we cover 380 * the full 32-bit address space defined by PCI of 381 * which we only make the first 64K available. 382 */ 383 pciio_ex = extent_create("pciio", 0, 0xffffffff, M_DEVBUF, 384 NULL, 0, EX_NOWAIT | EX_FILLED); 385 if (pciio_ex == NULL) 386 return; 387 extent_free(pciio_ex, 0, 0x10000, M_NOWAIT); 388 } 389 390 if (pcimem_ex == NULL) { 391 pcimem_ex = extent_create("pcimem", 0, 0xffffffff, M_DEVBUF, 392 NULL, 0, EX_NOWAIT); 393 if (pcimem_ex == NULL) 394 return; 395 396 for (bmp = bios_memmap; bmp->type != BIOS_MAP_END; bmp++) { 397 /* 398 * Ignore address space beyond 4G. 399 */ 400 if (bmp->addr >= 0x100000000ULL) 401 continue; 402 size = bmp->size; 403 if (bmp->addr + size >= 0x100000000ULL) 404 size = 0x100000000ULL - bmp->addr; 405 406 /* Ignore zero-sized regions. */ 407 if (size == 0) 408 continue; 409 410 if (extent_alloc_region(pcimem_ex, bmp->addr, size, 411 EX_NOWAIT)) 412 printf("memory map conflict 0x%llx/0x%llx\n", 413 bmp->addr, bmp->size); 414 } 415 416 /* Take out the video buffer area and BIOS areas. */ 417 extent_alloc_region(pcimem_ex, IOM_BEGIN, IOM_SIZE, 418 EX_CONFLICTOK | EX_NOWAIT); 419 } 420 } 421