1 /* $NetBSD: pci_machdep.c,v 1.20 2002/09/27 15:36:22 provos Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. 5 * Copyright (c) 1994 Charles M. Hannum. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Charles M. Hannum. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Machine-specific functions for PCI autoconfiguration. 35 * 36 * On PCs, there are two methods of generating PCI configuration cycles. 37 * We try to detect the appropriate mechanism for this machine and set 38 * up a few function pointers to access the correct method directly. 39 * 40 * The configuration method can be hard-coded in the config file by 41 * using `options PCI_CONF_MODE=N', where `N' is the configuration mode 42 * as defined section 3.6.4.1, `Generating Configuration Cycles'. 43 */ 44 45 #include <sys/types.h> 46 #include <sys/param.h> 47 #include <sys/time.h> 48 #include <sys/systm.h> 49 #include <sys/errno.h> 50 #include <sys/device.h> 51 52 #include <uvm/uvm_extern.h> 53 54 #define _MACPPC_BUS_DMA_PRIVATE 55 #include <machine/bus.h> 56 57 #include <machine/bus.h> 58 #include <machine/pio.h> 59 #include <machine/intr.h> 60 61 #include <dev/pci/pcivar.h> 62 #include <dev/pci/pcireg.h> 63 64 #include <dev/ofw/openfirm.h> 65 #include <dev/ofw/ofw_pci.h> 66 67 static void fixpci __P((int, pci_chipset_tag_t)); 68 static int find_node_intr __P((int, u_int32_t *, u_int32_t *)); 69 70 /* 71 * PCI doesn't have any special needs; just use the generic versions 72 * of these functions. 73 */ 74 struct macppc_bus_dma_tag pci_bus_dma_tag = { 75 0, /* _bounce_thresh */ 76 _bus_dmamap_create, 77 _bus_dmamap_destroy, 78 _bus_dmamap_load, 79 _bus_dmamap_load_mbuf, 80 _bus_dmamap_load_uio, 81 _bus_dmamap_load_raw, 82 _bus_dmamap_unload, 83 NULL, /* _dmamap_sync */ 84 _bus_dmamem_alloc, 85 _bus_dmamem_free, 86 _bus_dmamem_map, 87 _bus_dmamem_unmap, 88 _bus_dmamem_mmap, 89 }; 90 91 void 92 pci_attach_hook(parent, self, pba) 93 struct device *parent, *self; 94 struct pcibus_attach_args *pba; 95 { 96 pci_chipset_tag_t pc = pba->pba_pc; 97 int bus = pba->pba_bus; 98 int node, nn, sz; 99 int32_t busrange[2]; 100 101 for (node = pc->node; node; node = nn) { 102 sz = OF_getprop(node, "bus-range", busrange, 8); 103 if (sz == 8 && busrange[0] == bus) { 104 fixpci(node, pc); 105 return; 106 } 107 if ((nn = OF_child(node)) != 0) 108 continue; 109 while ((nn = OF_peer(node)) == 0) { 110 node = OF_parent(node); 111 if (node == pc->node) 112 return; /* not found */ 113 } 114 } 115 } 116 117 int 118 pci_bus_maxdevs(pc, busno) 119 pci_chipset_tag_t pc; 120 int busno; 121 { 122 123 /* 124 * Bus number is irrelevant. Configuration Mechanism 1 is in 125 * use, can have devices 0-32 (i.e. the `normal' range). 126 */ 127 return 32; 128 } 129 130 pcitag_t 131 pci_make_tag(pc, bus, device, function) 132 pci_chipset_tag_t pc; 133 int bus, device, function; 134 { 135 pcitag_t tag; 136 137 if (bus >= 256 || device >= 32 || function >= 8) 138 panic("pci_make_tag: bad request"); 139 140 /* XXX magic number */ 141 tag = 0x80000000 | (bus << 16) | (device << 11) | (function << 8); 142 143 return tag; 144 } 145 146 void 147 pci_decompose_tag(pc, tag, bp, dp, fp) 148 pci_chipset_tag_t pc; 149 pcitag_t tag; 150 int *bp, *dp, *fp; 151 { 152 153 if (bp != NULL) 154 *bp = (tag >> 16) & 0xff; 155 if (dp != NULL) 156 *dp = (tag >> 11) & 0x1f; 157 if (fp != NULL) 158 *fp = (tag >> 8) & 0x07; 159 } 160 161 pcireg_t 162 pci_conf_read(pc, tag, reg) 163 pci_chipset_tag_t pc; 164 pcitag_t tag; 165 int reg; 166 { 167 168 return (*pc->conf_read)(pc, tag, reg); 169 } 170 171 void 172 pci_conf_write(pc, tag, reg, data) 173 pci_chipset_tag_t pc; 174 pcitag_t tag; 175 int reg; 176 pcireg_t data; 177 { 178 179 (*pc->conf_write)(pc, tag, reg, data); 180 } 181 182 int 183 pci_intr_map(pa, ihp) 184 struct pci_attach_args *pa; 185 pci_intr_handle_t *ihp; 186 { 187 int pin = pa->pa_intrpin; 188 int line = pa->pa_intrline; 189 190 if (pin == 0) { 191 /* No IRQ used. */ 192 goto bad; 193 } 194 195 if (pin > 4) { 196 printf("pci_intr_map: bad interrupt pin %d\n", pin); 197 goto bad; 198 } 199 200 /* 201 * Section 6.2.4, `Miscellaneous Functions', says that 255 means 202 * `unknown' or `no connection' on a PC. We assume that a device with 203 * `no connection' either doesn't have an interrupt (in which case the 204 * pin number should be 0, and would have been noticed above), or 205 * wasn't configured by the BIOS (in which case we punt, since there's 206 * no real way we can know how the interrupt lines are mapped in the 207 * hardware). 208 * 209 * XXX 210 * Since IRQ 0 is only used by the clock, and we can't actually be sure 211 * that the BIOS did its job, we also recognize that as meaning that 212 * the BIOS has not configured the device. 213 */ 214 if (line == 0 || line == 255) { 215 printf("pci_intr_map: no mapping for pin %c\n", '@' + pin); 216 goto bad; 217 } else { 218 if (line >= ICU_LEN) { 219 printf("pci_intr_map: bad interrupt line %d\n", line); 220 goto bad; 221 } 222 } 223 224 *ihp = line; 225 return 0; 226 227 bad: 228 *ihp = -1; 229 return 1; 230 } 231 232 const char * 233 pci_intr_string(pc, ih) 234 pci_chipset_tag_t pc; 235 pci_intr_handle_t ih; 236 { 237 static char irqstr[8]; /* 4 + 2 + NULL + sanity */ 238 239 if (ih == 0 || ih >= ICU_LEN) 240 panic("pci_intr_string: bogus handle 0x%x", ih); 241 242 sprintf(irqstr, "irq %d", ih); 243 return (irqstr); 244 245 } 246 247 const struct evcnt * 248 pci_intr_evcnt(pc, ih) 249 pci_chipset_tag_t pc; 250 pci_intr_handle_t ih; 251 { 252 253 /* XXX for now, no evcnt parent reported */ 254 return NULL; 255 } 256 257 void * 258 pci_intr_establish(pc, ih, level, func, arg) 259 pci_chipset_tag_t pc; 260 pci_intr_handle_t ih; 261 int level, (*func) __P((void *)); 262 void *arg; 263 { 264 265 if (ih == 0 || ih >= ICU_LEN) 266 panic("pci_intr_establish: bogus handle 0x%x", ih); 267 268 return intr_establish(ih, IST_LEVEL, level, func, arg); 269 } 270 271 void 272 pci_intr_disestablish(pc, cookie) 273 pci_chipset_tag_t pc; 274 void *cookie; 275 { 276 277 intr_disestablish(cookie); 278 } 279 280 #define pcibus(x) \ 281 (((x) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT) 282 #define pcidev(x) \ 283 (((x) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT) 284 #define pcifunc(x) \ 285 (((x) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT) 286 287 void 288 fixpci(parent, pc) 289 int parent; 290 pci_chipset_tag_t pc; 291 { 292 int node; 293 pcitag_t tag; 294 pcireg_t csr, intr; 295 int len, i; 296 int32_t irqs[4]; 297 struct { 298 u_int32_t phys_hi, phys_mid, phys_lo; 299 u_int32_t size_hi, size_lo; 300 } addr[8]; 301 302 for (node = OF_child(parent); node; node = OF_peer(node)) { 303 len = OF_getprop(node, "assigned-addresses", addr, 304 sizeof(addr)); 305 if (len < (int)sizeof(addr[0])) 306 continue; 307 308 tag = pci_make_tag(pc, pcibus(addr[0].phys_hi), 309 pcidev(addr[0].phys_hi), 310 pcifunc(addr[0].phys_hi)); 311 312 /* 313 * Make sure the IO and MEM enable bits are set in the CSR. 314 */ 315 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 316 csr &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); 317 318 for (i = 0; i < len / sizeof(addr[0]); i++) { 319 switch (addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) { 320 case OFW_PCI_PHYS_HI_SPACE_IO: 321 csr |= PCI_COMMAND_IO_ENABLE; 322 break; 323 324 case OFW_PCI_PHYS_HI_SPACE_MEM32: 325 case OFW_PCI_PHYS_HI_SPACE_MEM64: 326 csr |= PCI_COMMAND_MEM_ENABLE; 327 break; 328 } 329 } 330 331 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr); 332 333 /* 334 * Make sure the line register is programmed with the 335 * interrupt mapping. 336 */ 337 if (find_node_intr(node, &addr[0].phys_hi, irqs) == -1) 338 continue; 339 340 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 341 intr &= ~PCI_INTERRUPT_LINE_MASK; 342 intr |= irqs[0] & PCI_INTERRUPT_LINE_MASK; 343 pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr); 344 } 345 } 346 347 /* 348 * Find PCI IRQ of the node from OF tree. 349 */ 350 int 351 find_node_intr(node, addr, intr) 352 int node; 353 u_int32_t *addr, *intr; 354 { 355 int parent, len, mlen, iparent; 356 int match, i; 357 u_int32_t map[160], *mp; 358 u_int32_t imask[8], maskedaddr[8]; 359 u_int32_t icells; 360 char name[32]; 361 362 len = OF_getprop(node, "AAPL,interrupts", intr, 4) ; 363 if (len == 4) 364 return len; 365 366 parent = OF_parent(node); 367 len = OF_getprop(parent, "interrupt-map", map, sizeof(map)); 368 mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask)); 369 370 if (len == -1 || mlen == -1) 371 goto nomap; 372 373 #ifdef DIAGNOSTIC 374 if (mlen == sizeof(imask)) { 375 printf("interrupt-map too long\n"); 376 return -1; 377 } 378 #endif 379 380 /* mask addr by "interrupt-map-mask" */ 381 memcpy(maskedaddr, addr, mlen); 382 for (i = 0; i < mlen / 4; i++) 383 maskedaddr[i] &= imask[i]; 384 385 mp = map; 386 while (len > mlen) { 387 match = memcmp(maskedaddr, mp, mlen); 388 mp += mlen / 4; 389 len -= mlen; 390 391 /* 392 * We must read "#interrupt-cells" for each time because 393 * interrupt-parent may be different. 394 */ 395 iparent = *mp++; 396 len -= 4; 397 if (OF_getprop(iparent, "#interrupt-cells", &icells, 4) != 4) 398 goto nomap; 399 400 /* Found. */ 401 if (match == 0) { 402 memcpy(intr, mp, icells * 4); 403 return icells * 4; 404 } 405 406 mp += icells; 407 len -= icells * 4; 408 } 409 410 nomap: 411 /* 412 * If the node has no interrupt property and the parent is a 413 * pci-bridge, use parent's interrupt. This occurs on a PCI 414 * slot. (e.g. AHA-3940) 415 */ 416 memset(name, 0, sizeof(name)); 417 OF_getprop(parent, "name", name, sizeof(name)); 418 if (strcmp(name, "pci-bridge") == 0) { 419 len = OF_getprop(parent, "AAPL,interrupts", intr, 4) ; 420 if (len == 4) 421 return len; 422 /* 423 * XXX I don't know what is the correct local address. 424 * XXX Use the first entry for now. 425 */ 426 len = OF_getprop(parent, "interrupt-map", map, sizeof(map)); 427 if (len >= 36) { 428 addr = &map[5]; 429 return find_node_intr(parent, addr, intr); 430 } 431 } 432 433 /* XXX This may be wrong... */ 434 len = OF_getprop(node, "interrupts", intr, 4) ; 435 if (len == 4) 436 return len; 437 438 return -1; 439 } 440