pci_machdep.c revision 1.2
1/* $NetBSD: pci_machdep.c,v 1.2 1999/06/05 05:29:50 mrg Exp $ */ 2 3/* 4 * Copyright (c) 1999 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 = 0x4; 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/* commonly used */ 78#define TAG2BUS(tag) ((tag) >> 16) & 0xff; 79#define TAG2DEV(tag) ((tag) >> 11) & 0x1f; 80#define TAG2FN(tag) ((tag) >> 8) & 0x7; 81 82/* 83 * functions provided to the MI code. 84 */ 85 86void 87pci_attach_hook(parent, self, pba) 88 struct device *parent; 89 struct device *self; 90 struct pcibus_attach_args *pba; 91{ 92 pci_chipset_tag_t pc = pba->pba_pc; 93 struct psycho_pbm *pp = pc->cookie; 94 struct psycho_registers *pr; 95 pcitag_t tag; 96 char *name, *devtype; 97 u_int32_t hi, mid, lo, intr; 98 u_int32_t dev, fn, bus; 99 int node, i, n, *ip, *ap; 100 101 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), ("\npci_attach_hook:")); 102 103 /* 104 * ok, here we look in the OFW for each PCI device and fix it's 105 * "interrupt line" register to be useful. 106 */ 107 108 for (node = firstchild(pc->node); node; node = nextsibling(node)) { 109 pr = NULL; 110 ip = ap = NULL; 111 112 /* 113 * ok, for each child we get the "interrupts" property, 114 * which contains a value to match against later. 115 * XXX deal with multiple "interrupts" values XXX. 116 * then we get the "assigned-addresses" property which 117 * contains, in the first entry, the PCI bus, device and 118 * function associated with this node, which we use to 119 * generate a pcitag_t to use pci_conf_read() and 120 * pci_conf_write(). next, we get the 'reg" property 121 * which is structured like the following: 122 * u_int32_t phys_hi; 123 * u_int32_t phys_mid; 124 * u_int32_t phys_lo; 125 * u_int32_t size_hi; 126 * u_int32_t size_lo; 127 * we mask these values with the "interrupt-map-mask" 128 * property of our parent and them compare with each 129 * entry in the "interrupt-map" property (also of our 130 * parent) which is structred like the following: 131 * u_int32_t phys_hi; 132 * u_int32_t phys_mid; 133 * u_int32_t phys_lo; 134 * u_int32_t intr; 135 * int32_t child_node; 136 * u_int32_t child_intr; 137 * if there is an exact match with phys_hi, phys_mid, 138 * phys_lo and the interrupt, we have a match and we 139 * know that this interrupt's value is really the 140 * child_intr of the interrupt map entry. we put this 141 * into the PCI interrupt line register so that when 142 * the driver for this node wants to attach, we know 143 * it's INO already. 144 */ 145 146 name = getpropstring(node, "name"); 147 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), ("\n\tnode %x name `%s'", node, name)); 148 devtype = getpropstring(node, "device_type"); 149 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), (" devtype `%s':", devtype)); 150 151 /* ignore PCI bridges, we'll get them later */ 152 if (strcmp(devtype, "pci") == 0) 153 continue; 154 155 /* if there isn't any "interrupts" then we don't care to fix it */ 156 ip = NULL; 157 if (getprop(node, "interrupts", sizeof(int), &n, (void **)&ip)) 158 continue; 159 DPRINTF(SPDB_INTFIX, (" got interrupts")); 160 161 /* and if there isn't an "assigned-addresses" we can't find b/d/f */ 162 if (getprop(node, "assigned-addresses", sizeof(int), &n, 163 (void **)&ap)) 164 goto clean1; 165 DPRINTF(SPDB_INTFIX, (" got assigned-addresses")); 166 167 /* ok, and now the "reg" property, so we know what we're talking about. */ 168 if (getprop(node, "reg", sizeof(*pr), &n, 169 (void **)&pr)) 170 goto clean2; 171 DPRINTF(SPDB_INTFIX, (" got reg")); 172 173 bus = TAG2BUS(ap[0]); 174 dev = TAG2DEV(ap[0]); 175 fn = TAG2FN(ap[0]); 176 177 DPRINTF(SPDB_INTFIX, ("; bus %u dev %u fn %u", bus, dev, fn)); 178 179 tag = pci_make_tag(pc, bus, dev, fn); 180 181 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)); 182 DPRINTF(SPDB_INTFIX, ("\n\t; intmapmask: hi %x mid %x lo %x intr %x", pp->pp_intmapmask.phys_hi, pp->pp_intmapmask.phys_mid, 183 pp->pp_intmapmask.phys_lo, pp->pp_intmapmask.intr)); 184 185 hi = pr->phys_hi & pp->pp_intmapmask.phys_hi; 186 mid = pr->phys_mid & pp->pp_intmapmask.phys_mid; 187 lo = pr->phys_lo & pp->pp_intmapmask.phys_lo; 188 intr = *ip & pp->pp_intmapmask.intr; 189 190 DPRINTF(SPDB_INTFIX, ("\n\t; after: hi %x mid %x lo %x intr %x", hi, mid, lo, intr)); 191 192 for (i = 0; i < pp->pp_nintmap; i++) { 193 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, 194 pp->pp_intmap[i].phys_lo, pp->pp_intmap[i].intr)); 195 196 if (pp->pp_intmap[i].phys_hi != hi || 197 pp->pp_intmap[i].phys_mid != mid || 198 pp->pp_intmap[i].phys_lo != lo || 199 pp->pp_intmap[i].intr != intr) 200 continue; 201 DPRINTF(SPDB_INTFIX, ("... BINGO! ...")); 202 203 /* 204 * OK! we found match. pull out the old interrupt 205 * register, patch in the new value, and put it back. 206 */ 207 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 208 DPRINTF(SPDB_INTFIX, ("\n\t ; read %x from intreg", intr)); 209 210 intr = (intr & ~PCI_INTERRUPT_LINE_MASK) | 211 (pp->pp_intmap[i].child_intr & PCI_INTERRUPT_LINE_MASK); 212 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), ("\n\t ; gonna write %x to intreg", intr)); 213 214 pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr); 215 DPRINTF((SPDB_INTFIX|SPDB_INTMAP), ("\n\t ; reread %x from intreg", intr)); 216 break; 217 } 218 219 /* clean up */ 220 if (pr) 221 free(pr, M_DEVBUF); 222clean2: 223 if (ap) 224 free(ap, M_DEVBUF); 225clean1: 226 if (ip) 227 free(ip, M_DEVBUF); 228 } 229 DPRINTF(SPDB_INTFIX, ("\n")); 230} 231 232int 233pci_bus_maxdevs(pc, busno) 234 pci_chipset_tag_t pc; 235 int busno; 236{ 237 238 return 32; 239} 240 241pcitag_t 242pci_make_tag(pc, b, d, f) 243 pci_chipset_tag_t pc; 244 int b; 245 int d; 246 int f; 247{ 248 249 /* make me a useable offset */ 250 return (b << 16) | (d << 11) | (f << 8); 251} 252 253static int confaddr_ok __P((struct psycho_softc *, pcitag_t)); 254 255/* 256 * this function is a large hack. ideally, we should also trap accesses 257 * properly, but we have to avoid letting anything read various parts 258 * of bus 0 dev 0 fn 0 space or the machine may hang. so, even if we 259 * do properly implement PCI config access trap handling, this function 260 * should remain in place Just In Case. 261 */ 262static int 263confaddr_ok(sc, tag) 264 struct psycho_softc *sc; 265 pcitag_t tag; 266{ 267 int bus, dev, fn; 268 269 bus = TAG2BUS(tag); 270 dev = TAG2DEV(tag); 271 fn = TAG2FN(tag); 272 273 if (sc->sc_mode == PSYCHO_MODE_SABRE) { 274 /* 275 * bus 0 is only ok for dev 0 fn 0, dev 1 fn 0 and dev fn 1. 276 */ 277 if (bus == 0 && 278 ((dev == 0 && fn > 0) || 279 (dev == 1 && fn > 1) || 280 (dev > 1))) { 281 DPRINTF(SPDB_CONF, (" confaddr_ok: rejecting bus %d dev %d fn %d -", bus, dev, fn)); 282 return (0); 283 } 284 } else if (sc->sc_mode == PSYCHO_MODE_PSYCHO_A || 285 sc->sc_mode == PSYCHO_MODE_PSYCHO_B) { 286 /* 287 * make sure we are reading our own bus 288 */ 289 /* XXX??? */ 290 panic("confaddr_ok: can't do SUNW,psycho yet"); 291 } 292 return (1); 293} 294 295/* assume we are mapped little-endian/side-effect */ 296pcireg_t 297pci_conf_read(pc, tag, reg) 298 pci_chipset_tag_t pc; 299 pcitag_t tag; 300 int reg; 301{ 302 struct psycho_pbm *pp = pc->cookie; 303 struct psycho_softc *sc = pp->pp_sc; 304 u_int32_t data; 305 pcireg_t val; 306 307 DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx; reg %x; ", (long)tag, reg)); 308 DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x) ...", 309 bus_type_asi[sc->sc_configtag->type], 310 sc->sc_configaddr + tag + reg, (int)tag + reg)); 311 312 if (confaddr_ok(sc, tag) == 0) { 313 val = (pcireg_t)~0; 314 } else { 315#if 0 316 membar_sync(); 317 data = probeget(bus_type_asi[sc->sc_configtag->type], 318 sc->sc_configaddr + tag + reg, 4); 319 membar_sync(); 320 if (data == -1) 321 val = (pcireg_t)~0; 322 else 323 val = (pcireg_t)data; 324#else 325 membar_sync(); 326 val = bus_space_read_4(sc->sc_configtag, sc->sc_configaddr, 327 tag + reg); 328 membar_sync(); 329#endif 330 } 331 DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val)); 332 333 return (val); 334} 335 336void 337pci_conf_write(pc, tag, reg, data) 338 pci_chipset_tag_t pc; 339 pcitag_t tag; 340 int reg; 341 pcireg_t data; 342{ 343 struct psycho_pbm *pp = pc->cookie; 344 struct psycho_softc *sc = pp->pp_sc; 345 346 DPRINTF(SPDB_CONF, ("pci_conf_write: tag %ld; reg %d; data %d; ", (long)tag, reg, (int)data)); 347 DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x)\n", 348 bus_type_asi[sc->sc_configtag->type], 349 sc->sc_configaddr + tag + reg, (int)tag + reg)); 350 351 if (confaddr_ok(sc, tag) == 0) 352 panic("pci_conf_write: bad addr"); 353 354 membar_sync(); 355#if 0 356 probeset(bus_type_asi[sc->sc_configtag->type], 357 sc->sc_configaddr + tag + reg, 4, data); 358#else 359 bus_space_write_4(sc->sc_configtag, sc->sc_configaddr, tag + reg, data); 360#endif 361 membar_sync(); 362} 363 364/* 365 * interrupt mapping foo. 366 */ 367int 368pci_intr_map(pc, tag, pin, line, ihp) 369 pci_chipset_tag_t pc; 370 pcitag_t tag; 371 int pin; 372 int line; 373 pci_intr_handle_t *ihp; 374{ 375 struct psycho_pbm *pp = pc->cookie; 376 int rv; 377 378 DPRINTF(SPDB_INTR, ("pci_intr_map: tag %x; pin %d; line %d", (u_int)tag, pin, line)); 379 380 if (line == 255 || pin == 0) { 381 *ihp = -1; 382 rv = 1; 383 goto out; 384 } 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