1 /* $NetBSD: pci_machdep.c,v 1.25 2001/10/17 22:16:41 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1999, 2000 Matthew R. Green 5 * 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 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, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * functions expected by the MI PCI code. 33 */ 34 35 #ifdef DEBUG 36 #define SPDB_CONF 0x01 37 #define SPDB_INTR 0x04 38 #define SPDB_INTMAP 0x08 39 #define SPDB_INTFIX 0x10 40 #define SPDB_PROBE 0x20 41 int sparc_pci_debug = 0x0; 42 #define DPRINTF(l, s) do { if (sparc_pci_debug & l) printf s; } while (0) 43 #else 44 #define DPRINTF(l, s) 45 #endif 46 47 #include <sys/types.h> 48 #include <sys/param.h> 49 #include <sys/time.h> 50 #include <sys/systm.h> 51 #include <sys/errno.h> 52 #include <sys/device.h> 53 #include <sys/malloc.h> 54 55 #define _SPARC_BUS_DMA_PRIVATE 56 #include <machine/bus.h> 57 #include <machine/autoconf.h> 58 #include <machine/openfirm.h> 59 60 #include <dev/pci/pcivar.h> 61 #include <dev/pci/pcireg.h> 62 63 #include <dev/ofw/ofw_pci.h> 64 65 #include <sparc64/dev/iommureg.h> 66 #include <sparc64/dev/iommuvar.h> 67 #include <sparc64/dev/psychoreg.h> 68 #include <sparc64/dev/psychovar.h> 69 70 /* this is a base to be copied */ 71 struct sparc_pci_chipset _sparc_pci_chipset = { 72 NULL, 73 }; 74 75 /* 76 * functions provided to the MI code. 77 */ 78 79 void 80 pci_attach_hook(parent, self, pba) 81 struct device *parent; 82 struct device *self; 83 struct pcibus_attach_args *pba; 84 { 85 /* Don't do nothing */ 86 } 87 88 int 89 pci_bus_maxdevs(pc, busno) 90 pci_chipset_tag_t pc; 91 int busno; 92 { 93 94 return 32; 95 } 96 97 #ifdef __PCI_BUS_DEVORDER 98 int 99 pci_bus_devorder(pc, busno, devs) 100 pci_chipset_tag_t pc; 101 int busno; 102 char *devs; 103 { 104 struct ofw_pci_register reg; 105 int node, len, device, i = 0; 106 u_int32_t done = 0; 107 #ifdef DEBUG 108 char name[80]; 109 #endif 110 111 node = pc->curnode; 112 #ifdef DEBUG 113 if (sparc_pci_debug & SPDB_PROBE) { 114 OF_getprop(node, "name", &name, sizeof(name)); 115 printf("pci_bus_devorder: curnode %x %s\n", node, name); 116 } 117 #endif 118 /* 119 * Initially, curnode is the root of the pci tree. As we 120 * attach bridges, curnode should be set to that of the bridge. 121 */ 122 for (node = OF_child(node); node; node = OF_peer(node)) { 123 len = OF_getproplen(node, "reg"); 124 if (len < sizeof(reg)) 125 continue; 126 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len) 127 panic("pci_probe_bus: OF_getprop len botch"); 128 129 device = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi); 130 131 if (done & (1 << device)) 132 continue; 133 134 devs[i++] = device; 135 done |= 1 << device; 136 #ifdef DEBUG 137 if (sparc_pci_debug & SPDB_PROBE) { 138 OF_getprop(node, "name", &name, sizeof(name)); 139 printf("pci_bus_devorder: adding %x %s\n", node, name); 140 } 141 #endif 142 if (i == 32) 143 break; 144 } 145 if (i < 32) 146 devs[i] = -1; 147 148 return i; 149 } 150 #endif 151 152 #ifdef __PCI_DEV_FUNCORDER 153 int 154 pci_dev_funcorder(pc, busno, device, funcs) 155 pci_chipset_tag_t pc; 156 int busno; 157 int device; 158 char *funcs; 159 { 160 struct ofw_pci_register reg; 161 int node, len, i = 0; 162 #ifdef DEBUG 163 char name[80]; 164 #endif 165 166 node = pc->curnode; 167 #ifdef DEBUG 168 if (sparc_pci_debug & SPDB_PROBE) { 169 OF_getprop(node, "name", &name, sizeof(name)); 170 printf("pci_bus_funcorder: curnode %x %s\n", node, name); 171 } 172 #endif 173 /* 174 * Initially, curnode is the root of the pci tree. As we 175 * attach bridges, curnode should be set to that of the bridge. 176 * 177 * Note this search is almost exactly the same as pci_bus_devorder()'s, 178 * except that we limit the search to only those with a matching 179 * "device" number. 180 */ 181 for (node = OF_child(node); node; node = OF_peer(node)) { 182 len = OF_getproplen(node, "reg"); 183 if (len < sizeof(reg)) 184 continue; 185 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len) 186 panic("pci_probe_bus: OF_getprop len botch"); 187 188 if (device != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi)) 189 continue; 190 191 funcs[i++] = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi); 192 #ifdef DEBUG 193 if (sparc_pci_debug & SPDB_PROBE) { 194 OF_getprop(node, "name", &name, sizeof(name)); 195 printf("pci_bus_funcorder: adding %x %s\n", node, name); 196 } 197 #endif 198 if (i == 8) 199 break; 200 } 201 if (i < 8) 202 funcs[i] = -1; 203 204 return i; 205 } 206 #endif 207 208 pcitag_t 209 pci_make_tag(pc, b, d, f) 210 pci_chipset_tag_t pc; 211 int b; 212 int d; 213 int f; 214 { 215 struct ofw_pci_register reg; 216 pcitag_t tag; 217 int busrange[2]; 218 int node, len; 219 #ifdef DEBUG 220 char name[80]; 221 bzero(name, sizeof(name)); 222 #endif 223 224 /* 225 * Hunt for the node that corresponds to this device 226 * 227 * We could cache this info in an array in the parent 228 * device... except then we have problems with devices 229 * attached below pci-pci bridges, and we would need to 230 * add special code to the pci-pci bridge to cache this 231 * info. 232 */ 233 234 tag = PCITAG_CREATE(-1, b, d, f); 235 node = pc->rootnode; 236 /* 237 * First make sure we're on the right bus. If our parent 238 * has a bus-range property and we're not in the range, 239 * then we're obviously on the wrong bus. So go up one 240 * level. 241 */ 242 #ifdef DEBUG 243 if (sparc_pci_debug & SPDB_PROBE) { 244 OF_getprop(node, "name", &name, sizeof(name)); 245 printf("curnode %x %s\n", node, name); 246 } 247 #endif 248 #if 0 249 while ((OF_getprop(OF_parent(node), "bus-range", (void *)&busrange, 250 sizeof(busrange)) == sizeof(busrange)) && 251 (b < busrange[0] || b > busrange[1])) { 252 /* Out of range, go up one */ 253 node = OF_parent(node); 254 #ifdef DEBUG 255 if (sparc_pci_debug & SPDB_PROBE) { 256 OF_getprop(node, "name", &name, sizeof(name)); 257 printf("going up to node %x %s\n", node, name); 258 } 259 #endif 260 } 261 #endif 262 /* 263 * Now traverse all peers until we find the node or we find 264 * the right bridge. 265 * 266 * XXX We go up one and down one to make sure nobody's missed. 267 * but this should not be necessary. 268 */ 269 for (node = ((node)); node; node = OF_peer(node)) { 270 271 #ifdef DEBUG 272 if (sparc_pci_debug & SPDB_PROBE) { 273 OF_getprop(node, "name", &name, sizeof(name)); 274 printf("checking node %x %s\n", node, name); 275 } 276 #endif 277 278 #if 1 279 /* 280 * Check for PCI-PCI bridges. If the device we want is 281 * in the bus-range for that bridge, work our way down. 282 */ 283 while ((OF_getprop(node, "bus-range", (void *)&busrange, 284 sizeof(busrange)) == sizeof(busrange)) && 285 (b >= busrange[0] && b <= busrange[1])) { 286 /* Go down 1 level */ 287 node = OF_child(node); 288 #ifdef DEBUG 289 if (sparc_pci_debug & SPDB_PROBE) { 290 OF_getprop(node, "name", &name, sizeof(name)); 291 printf("going down to node %x %s\n", 292 node, name); 293 } 294 #endif 295 } 296 #endif 297 /* 298 * We only really need the first `reg' property. 299 * 300 * For simplicity, we'll query the `reg' when we 301 * need it. Otherwise we could malloc() it, but 302 * that gets more complicated. 303 */ 304 len = OF_getproplen(node, "reg"); 305 if (len < sizeof(reg)) 306 continue; 307 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len) 308 panic("pci_probe_bus: OF_getprop len botch"); 309 310 if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi)) 311 continue; 312 if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi)) 313 continue; 314 if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi)) 315 continue; 316 317 /* Got a match */ 318 tag = PCITAG_CREATE(node, b, d, f); 319 320 /* 321 * Record the node. This has two effects: 322 * 323 * 1) We don't have to search as far. 324 * 2) pci_bus_devorder will scan the right bus. 325 */ 326 pc->curnode = node; 327 328 /* Enable all the different spaces for this device */ 329 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, 330 PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE| 331 PCI_COMMAND_IO_ENABLE); 332 DPRINTF(SPDB_PROBE, ("found node %x %s\n", node, name)); 333 return (tag); 334 } 335 /* No device found -- return a dead tag */ 336 return (tag); 337 } 338 339 /* assume we are mapped little-endian/side-effect */ 340 pcireg_t 341 pci_conf_read(pc, tag, reg) 342 pci_chipset_tag_t pc; 343 pcitag_t tag; 344 int reg; 345 { 346 struct psycho_pbm *pp = pc->cookie; 347 struct psycho_softc *sc = pp->pp_sc; 348 pcireg_t val = (pcireg_t)~0; 349 350 DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx reg %x ", 351 (long)tag, reg)); 352 if (PCITAG_NODE(tag) != -1) { 353 DPRINTF(SPDB_CONF, ("asi=%x addr=%qx (offset=%x) ...", 354 bus_type_asi[sc->sc_configtag->type], 355 (long long)(sc->sc_configaddr + 356 PCITAG_OFFSET(tag) + reg), 357 (int)PCITAG_OFFSET(tag) + reg)); 358 359 val = bus_space_read_4(sc->sc_configtag, sc->sc_configaddr, 360 PCITAG_OFFSET(tag) + reg); 361 } 362 #ifdef DEBUG 363 else DPRINTF(SPDB_CONF, ("pci_conf_read: bogus pcitag %x\n", 364 (int)PCITAG_OFFSET(tag))); 365 #endif 366 DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val)); 367 368 return (val); 369 } 370 371 void 372 pci_conf_write(pc, tag, reg, data) 373 pci_chipset_tag_t pc; 374 pcitag_t tag; 375 int reg; 376 pcireg_t data; 377 { 378 struct psycho_pbm *pp = pc->cookie; 379 struct psycho_softc *sc = pp->pp_sc; 380 381 DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ", 382 (long)PCITAG_OFFSET(tag), reg, (int)data)); 383 DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x)\n", 384 bus_type_asi[sc->sc_configtag->type], 385 (long long)(sc->sc_configaddr + PCITAG_OFFSET(tag) + reg), 386 (int)PCITAG_OFFSET(tag) + reg)); 387 388 /* If we don't know it, just punt it. */ 389 if (PCITAG_NODE(tag) == -1) { 390 DPRINTF(SPDB_CONF, ("pci_conf_write: bad addr")); 391 return; 392 } 393 394 bus_space_write_4(sc->sc_configtag, sc->sc_configaddr, 395 PCITAG_OFFSET(tag) + reg, data); 396 } 397 398 /* 399 * interrupt mapping foo. 400 * XXX: how does this deal with multiple interrupts for a device? 401 */ 402 int 403 pci_intr_map(pa, ihp) 404 struct pci_attach_args *pa; 405 pci_intr_handle_t *ihp; 406 { 407 pcitag_t tag = pa->pa_tag; 408 int interrupts; 409 int len, node = PCITAG_NODE(tag); 410 char devtype[30]; 411 412 len = OF_getproplen(node, "interrupts"); 413 if (len < sizeof(interrupts)) { 414 DPRINTF(SPDB_INTMAP, 415 ("pci_intr_map: interrupts len %d too small\n", len)); 416 return (ENODEV); 417 } 418 if (OF_getprop(node, "interrupts", (void *)&interrupts, 419 sizeof(interrupts)) != len) { 420 DPRINTF(SPDB_INTMAP, 421 ("pci_intr_map: could not read interrupts\n")); 422 return (ENODEV); 423 } 424 425 if (OF_mapintr(node, &interrupts, sizeof(interrupts), 426 sizeof(interrupts)) < 0) { 427 printf("OF_mapintr failed\n"); 428 } 429 /* Try to find an IPL for this type of device. */ 430 if (OF_getprop(node, "device_type", &devtype, sizeof(devtype)) > 0) { 431 for (len = 0; intrmap[len].in_class; len++) 432 if (strcmp(intrmap[len].in_class, devtype) == 0) { 433 interrupts |= INTLEVENCODE(intrmap[len].in_lev); 434 break; 435 } 436 } 437 438 /* XXXX -- we use the ino. What if there is a valid IGN? */ 439 *ihp = interrupts; 440 return (0); 441 } 442 443 const char * 444 pci_intr_string(pc, ih) 445 pci_chipset_tag_t pc; 446 pci_intr_handle_t ih; 447 { 448 static char str[16]; 449 450 DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih)); 451 sprintf(str, "ivec %x", ih); 452 DPRINTF(SPDB_INTR, ("; returning %s\n", str)); 453 454 return (str); 455 } 456 457 const struct evcnt * 458 pci_intr_evcnt(pc, ih) 459 pci_chipset_tag_t pc; 460 pci_intr_handle_t ih; 461 { 462 463 /* XXX for now, no evcnt parent reported */ 464 return NULL; 465 } 466 467 void * 468 pci_intr_establish(pc, ih, level, func, arg) 469 pci_chipset_tag_t pc; 470 pci_intr_handle_t ih; 471 int level; 472 int (*func) __P((void *)); 473 void *arg; 474 { 475 void *cookie; 476 struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie; 477 478 DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d", (u_long)ih, level)); 479 cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg); 480 481 DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie)); 482 return (cookie); 483 } 484 485 void 486 pci_intr_disestablish(pc, cookie) 487 pci_chipset_tag_t pc; 488 void *cookie; 489 { 490 491 DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie)); 492 493 /* XXX */ 494 panic("can't disestablish PCI interrupts yet"); 495 } 496