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