pci_machdep.c revision 1.21
1/* $NetBSD: pci_machdep.c,v 1.21 2001/03/21 01:33:48 mrg 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 40int sparc_pci_debug = 0x0; 41#define DPRINTF(l, s) do { if (sparc_pci_debug & l) printf s; } while (0) 42#else 43#define DPRINTF(l, s) 44#endif 45 46#include <sys/types.h> 47#include <sys/param.h> 48#include <sys/time.h> 49#include <sys/systm.h> 50#include <sys/errno.h> 51#include <sys/device.h> 52#include <sys/malloc.h> 53 54#define _SPARC_BUS_DMA_PRIVATE 55#include <machine/bus.h> 56#include <machine/autoconf.h> 57 58#include <dev/pci/pcivar.h> 59#include <dev/pci/pcireg.h> 60 61#include <dev/ofw/openfirm.h> 62#include <dev/ofw/ofw_pci.h> 63 64#include <sparc64/dev/iommureg.h> 65#include <sparc64/dev/iommuvar.h> 66#include <sparc64/dev/psychoreg.h> 67#include <sparc64/dev/psychovar.h> 68 69/* this is a base to be copied */ 70struct sparc_pci_chipset _sparc_pci_chipset = { 71 NULL, 72}; 73 74/* 75 * functions provided to the MI code. 76 */ 77 78void 79pci_attach_hook(parent, self, pba) 80 struct device *parent; 81 struct device *self; 82 struct pcibus_attach_args *pba; 83{ 84 pci_chipset_tag_t pc = pba->pba_pc; 85 struct psycho_pbm *pp = pc->cookie; 86 struct psycho_registers *pr; 87 pcitag_t tag; 88 char *name, *devtype; 89 u_int32_t hi, mid, lo, intr, line; 90 u_int32_t dev, fn, bus; 91 int node, i, n, *ip, *ap; 92 93 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), ("\npci_attach_hook:")); 94 95 /* 96 * ok, here we look in the OFW for each PCI device and fix it's 97 * "interrupt line" register to be useful. 98 */ 99 100 for (node = firstchild(pc->node); node; node = nextsibling(node)) { 101 pr = NULL; 102 ip = ap = NULL; 103 104 /* 105 * ok, for each child we get the "interrupts" property, 106 * which contains a value to match against later. 107 * XXX deal with multiple "interrupts" values XXX. 108 * then we get the "assigned-addresses" property which 109 * contains, in the first entry, the PCI bus, device and 110 * function associated with this node, which we use to 111 * generate a pcitag_t to use pci_conf_read() and 112 * pci_conf_write(). next, we get the 'reg" property 113 * which is structured like the following: 114 * u_int32_t phys_hi; 115 * u_int32_t phys_mid; 116 * u_int32_t phys_lo; 117 * u_int32_t size_hi; 118 * u_int32_t size_lo; 119 * we mask these values with the "interrupt-map-mask" 120 * property of our parent and them compare with each 121 * entry in the "interrupt-map" property (also of our 122 * parent) which is structred like the following: 123 * u_int32_t phys_hi; 124 * u_int32_t phys_mid; 125 * u_int32_t phys_lo; 126 * u_int32_t intr; 127 * int32_t child_node; 128 * u_int32_t child_intr; 129 * if there is an exact match with phys_hi, phys_mid, 130 * phys_lo and the interrupt, we have a match and we 131 * know that this interrupt's value is really the 132 * child_intr of the interrupt map entry. we put this 133 * into the PCI interrupt line register so that when 134 * the driver for this node wants to attach, we know 135 * it's INO already. 136 */ 137 138 name = getpropstring(node, "name"); 139 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), ("\n\tnode %x name `%s'", node, name)); 140 devtype = getpropstring(node, "device_type"); 141 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), (" devtype `%s':", devtype)); 142 143 /* ignore PCI bridges, we'll get them later */ 144 if (strcmp(devtype, "pci") == 0) 145 continue; 146 147 /* if there isn't any "interrupts" then we don't care to fix it */ 148 ip = NULL; 149 if (getprop(node, "interrupts", sizeof(int), &n, (void **)&ip)) 150 continue; 151 DPRINTF(SPDB_INTFIX, (" got interrupts")); 152 153 /* and if there isn't an "assigned-addresses" we can't find b/d/f */ 154 if (getprop(node, "assigned-addresses", sizeof(int), &n, 155 (void **)&ap)) 156 goto clean1; 157 DPRINTF(SPDB_INTFIX, (" got assigned-addresses")); 158 159 /* ok, and now the "reg" property, so we know what we're talking about. */ 160 if (getprop(node, "reg", sizeof(*pr), &n, 161 (void **)&pr)) 162 goto clean2; 163 DPRINTF(SPDB_INTFIX, (" got reg")); 164 165 bus = TAG2BUS(ap[0]); 166 dev = TAG2DEV(ap[0]); 167 fn = TAG2FN(ap[0]); 168 169 DPRINTF(SPDB_INTFIX, ("; bus %u dev %u fn %u", bus, dev, fn)); 170 171 tag = pci_make_tag(pc, bus, dev, fn); 172 173 DPRINTF(SPDB_INTFIX, ("; tag %08x\n\t; reg: hi %x mid %x lo %x intr %x", tag, pr->phys_hi, pr->phys_mid, pr->phys_lo, *ip)); 174 175 /* 176 * if there is no interrupt-map property in the parent, we must 177 * assume our "interrupts" property is valid. 178 */ 179 if (pp->pp_nintmap == 0) { 180 intr = *ip; 181 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), ("\n\t ; no interrupt-map, using intr %x", *ip)); 182 goto bingo; 183 } 184 185 DPRINTF(SPDB_INTFIX, ("\n\t; intmapmask: hi %x mid %x lo %x intr %x", pp->pp_intmapmask.phys_hi, pp->pp_intmapmask.phys_mid, 186 pp->pp_intmapmask.phys_lo, pp->pp_intmapmask.intr)); 187 188 hi = pr->phys_hi & pp->pp_intmapmask.phys_hi; 189 mid = pr->phys_mid & pp->pp_intmapmask.phys_mid; 190 lo = pr->phys_lo & pp->pp_intmapmask.phys_lo; 191 intr = *ip & pp->pp_intmapmask.intr; 192 193 DPRINTF(SPDB_INTFIX, ("\n\t; after: hi %x mid %x lo %x intr %x", hi, mid, lo, intr)); 194 195 for (i = 0; i < pp->pp_nintmap; i++) { 196 DPRINTF(SPDB_INTFIX, ("\n\t\tmatching for: hi %x mid %x lo %x intr %x", pp->pp_intmap[i].phys_hi, pp->pp_intmap[i].phys_mid, 197 pp->pp_intmap[i].phys_lo, pp->pp_intmap[i].intr)); 198 199 if (pp->pp_intmap[i].phys_hi != hi || 200 pp->pp_intmap[i].phys_mid != mid || 201 pp->pp_intmap[i].phys_lo != lo || 202 pp->pp_intmap[i].intr != intr) 203 continue; 204 intr = pp->pp_intmap[i].child_intr; 205 DPRINTF(SPDB_INTFIX, ("... BINGO! ...")); 206 207 bingo: 208 /* 209 * OK! we found match. pull out the old interrupt 210 * register, patch in the new value, and put it back. 211 */ 212 line = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 213 DPRINTF(SPDB_INTFIX, ("\n\t ; read %x from intreg", line)); 214 215 line = PCI_INTERRUPT_CODE(PCI_INTERRUPT_LATENCY(line), 216 PCI_INTERRUPT_GRANT(line), 217 PCI_INTERRUPT_PIN(line), 218 PCI_INTERRUPT_LINE(intr)); 219 220 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), ("\n\t ; gonna write %x to intreg", line)); 221 pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr); 222 break; 223 } 224 if (i == pp->pp_nintmap) { 225 /* 226 * Not matched by parent interrupt map. If the 227 * interrupt property has the INTMAP_OBIO bit 228 * set, assume the PROM has (wrongly) supplied it 229 * in the parent's bus format, rather than as a 230 * PCI interrupt line number. 231 * 232 * This seems to be an issue only with the 233 * psycho host-to-pci bridge. 234 */ 235 if (pp->pp_sc->sc_mode == PSYCHO_MODE_PSYCHO && 236 (*ip & INTMAP_OBIO) != 0) { 237 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), 238 ("\n\t; PSYCHO: no match but obio interrupt in parent format")); 239 240 intr = *ip; 241 i = -1; 242 goto bingo; /* hackish */ 243 } 244 } 245 246 /* enable mem & dma if not already */ 247 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, 248 PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE|PCI_COMMAND_IO_ENABLE); 249 250 251 /* clean up */ 252 if (pr) 253 free(pr, M_DEVBUF); 254clean2: 255 if (ap) 256 free(ap, M_DEVBUF); 257clean1: 258 if (ip) 259 free(ip, M_DEVBUF); 260 } 261 DPRINTF(SPDB_INTFIX, ("\n")); 262} 263 264int 265pci_bus_maxdevs(pc, busno) 266 pci_chipset_tag_t pc; 267 int busno; 268{ 269 270 return 32; 271} 272 273#ifdef __PCI_BUS_DEVORDER 274int 275pci_bus_devorder(pc, busno, devs) 276 pci_chipset_tag_t pc; 277 int busno; 278 char *devs; 279{ 280 struct ofw_pci_register reg0; 281 int node, len, device, i = 0; 282 u_int32_t done = 0; 283 284 for (node = OF_child(pc->node); node; node = OF_peer(node)) { 285 len = OF_getproplen(node, "reg"); 286 if (len < sizeof(reg0)) 287 continue; 288 if (OF_getprop(node, "reg", (void *)®0, sizeof(reg0)) != len) 289 panic("pci_probe_bus: OF_getprop len botch"); 290 291 device = OFW_PCI_PHYS_HI_DEVICE(reg0.phys_hi); 292 293 if (done & (1 << device)) 294 continue; 295 296 devs[i++] = device; 297 done |= 1 << device; 298 if (i == 32) 299 break; 300 } 301 if (i < 32) 302 devs[i] = -1; 303 304 return i; 305} 306#endif 307 308#ifdef __PCI_DEV_FUNCORDER 309int 310pci_dev_funcorder(pc, busno, device, funcs) 311 pci_chipset_tag_t pc; 312 int busno; 313 int device; 314 char *funcs; 315{ 316 struct ofw_pci_register reg0; 317 int node, len, i = 0; 318 319 for (node = OF_child(pc->node); node; node = OF_peer(node)) { 320 len = OF_getproplen(node, "reg"); 321 if (len < sizeof(reg0)) 322 continue; 323 if (OF_getprop(node, "reg", (void *)®0, sizeof(reg0)) != len) 324 panic("pci_probe_bus: OF_getprop len botch"); 325 326 if (device != OFW_PCI_PHYS_HI_DEVICE(reg0.phys_hi)) 327 continue; 328 329 funcs[i++] = OFW_PCI_PHYS_HI_FUNCTION(reg0.phys_hi); 330 if (i == 8) 331 break; 332 } 333 if (i < 8) 334 funcs[i] = -1; 335 336 return i; 337} 338#endif 339 340pcitag_t 341pci_make_tag(pc, b, d, f) 342 pci_chipset_tag_t pc; 343 int b; 344 int d; 345 int f; 346{ 347 348 /* make me a useable offset */ 349 return (b << 16) | (d << 11) | (f << 8); 350} 351 352static int confaddr_ok __P((struct psycho_softc *, pcitag_t)); 353 354/* 355 * this function is a large hack. ideally, we should also trap accesses 356 * properly, but we have to avoid letting anything read various parts 357 * of bus 0 dev 0 fn 0 space or the machine may hang. so, even if we 358 * do properly implement PCI config access trap handling, this function 359 * should remain in place Just In Case. 360 */ 361static int 362confaddr_ok(sc, tag) 363 struct psycho_softc *sc; 364 pcitag_t tag; 365{ 366 int bus, dev, fn; 367 368 bus = TAG2BUS(tag); 369 dev = TAG2DEV(tag); 370 fn = TAG2FN(tag); 371 372 if (sc->sc_mode == PSYCHO_MODE_SABRE) { 373 /* 374 * bus 0 is only ok for dev 0 fn 0, dev 1 fn 0 and dev fn 1. 375 */ 376 if (bus == 0 && 377 ((dev == 0 && fn > 0) || 378 (dev == 1 && fn > 1) || 379 (dev > 1))) { 380 DPRINTF(SPDB_CONF, (" confaddr_ok: rejecting bus %d dev %d fn %d -", bus, dev, fn)); 381 return (0); 382 } 383 } else if (sc->sc_mode == PSYCHO_MODE_PSYCHO) { 384 /* 385 * make sure we are reading our own bus 386 */ 387 /* XXX??? */ 388 paddr_t addr = sc->sc_configaddr + tag; 389 int asi = bus_type_asi[sc->sc_configtag->type]; 390 if (probeget(addr, asi, 4) == -1) { 391 DPRINTF(SPDB_CONF, (" confaddr_ok: rejecting bus %d dev %d fn %d -", bus, dev, fn)); 392 return (0); 393 } 394 } 395 return (1); 396} 397 398/* assume we are mapped little-endian/side-effect */ 399pcireg_t 400pci_conf_read(pc, tag, reg) 401 pci_chipset_tag_t pc; 402 pcitag_t tag; 403 int reg; 404{ 405 struct psycho_pbm *pp = pc->cookie; 406 struct psycho_softc *sc = pp->pp_sc; 407 pcireg_t val; 408 409 DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx; reg %x; ", (long)tag, reg)); 410 DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x) ...", 411 bus_type_asi[sc->sc_configtag->type], 412 (long long)(sc->sc_configaddr + tag + reg), (int)tag + reg)); 413 414 if (confaddr_ok(sc, tag) == 0) { 415 val = (pcireg_t)~0; 416 } else { 417 membar_sync(); 418 val = bus_space_read_4(sc->sc_configtag, sc->sc_configaddr, 419 tag + reg); 420 membar_sync(); 421 } 422 DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val)); 423 424 return (val); 425} 426 427void 428pci_conf_write(pc, tag, reg, data) 429 pci_chipset_tag_t pc; 430 pcitag_t tag; 431 int reg; 432 pcireg_t data; 433{ 434 struct psycho_pbm *pp = pc->cookie; 435 struct psycho_softc *sc = pp->pp_sc; 436 437 DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ", (long)tag, reg, (int)data)); 438 DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x)\n", 439 bus_type_asi[sc->sc_configtag->type], 440 (long long)(sc->sc_configaddr + tag + reg), (int)tag + reg)); 441 442 if (confaddr_ok(sc, tag) == 0) 443 panic("pci_conf_write: bad addr"); 444 445 membar_sync(); 446 bus_space_write_4(sc->sc_configtag, sc->sc_configaddr, tag + reg, data); 447 membar_sync(); 448} 449 450/* 451 * interrupt mapping foo. 452 * XXX: how does this deal with multiple interrupts for a device? 453 */ 454int 455pci_intr_map(pa, ihp) 456 struct pci_attach_args *pa; 457 pci_intr_handle_t *ihp; 458{ 459 int rv, pin, line; 460 461 pin = pa->pa_intrpin; 462 line = pa->pa_intrline; 463 464 DPRINTF(SPDB_INTMAP, ("pci_intr_map: dev %u fn %u: ", pa->pa_device, 465 pa->pa_function)); 466 /* 467 * XXX 468 * UltraSPARC PCI does not use PCI_INTERRUPT_REG, but we have 469 * used this space for our own purposes... 470 */ 471 DPRINTF(SPDB_INTR, ("pci_intr_map: tag %lx; line %d", 472 (long)pa->pa_intrtag, line)); 473 474 if (line >= 0x40) { 475 *ihp = -1; 476 rv = 1; 477 goto out; 478 } 479 if (pin > 4) 480 panic("pci_intr_map: pin > 4"); 481 482 (*ihp) = line & 0x3f; 483 rv = 0; 484out: 485 DPRINTF(SPDB_INTR, ("; handle = %x; returning %d\n", (u_int)*ihp, rv)); 486 return (rv); 487} 488 489const char * 490pci_intr_string(pc, ih) 491 pci_chipset_tag_t pc; 492 pci_intr_handle_t ih; 493{ 494 static char str[16]; 495 496 DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih)); 497 if (ih < 0 || ih >= 0x40) { 498 printf("\n"); /* i'm *so* beautiful */ 499 panic("pci_intr_string: bogus handle\n"); 500 } 501 sprintf(str, "ipl %u", ih); 502 DPRINTF(SPDB_INTR, ("; returning %s\n", str)); 503 504 return (str); 505} 506 507const struct evcnt * 508pci_intr_evcnt(pc, ih) 509 pci_chipset_tag_t pc; 510 pci_intr_handle_t ih; 511{ 512 513 /* XXX for now, no evcnt parent reported */ 514 return NULL; 515} 516 517void * 518pci_intr_establish(pc, ih, level, func, arg) 519 pci_chipset_tag_t pc; 520 pci_intr_handle_t ih; 521 int level; 522 int (*func) __P((void *)); 523 void *arg; 524{ 525 void *cookie; 526 struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie; 527 528 DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d", (u_long)ih, level)); 529 cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg); 530 531 DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie)); 532 return (cookie); 533} 534 535void 536pci_intr_disestablish(pc, cookie) 537 pci_chipset_tag_t pc; 538 void *cookie; 539{ 540 541 DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie)); 542 543 /* XXX */ 544 panic("can't disestablish PCI interrupts yet"); 545} 546