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