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