pci_machdep.c revision 1.27
1/* $NetBSD: pci_machdep.c,v 1.27 2002/05/06 22:18:51 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#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 335pcitag_t 336ofpci_make_tag(pc, node, b, d, f) 337 pci_chipset_tag_t pc; 338 int node; 339 int b; 340 int d; 341 int f; 342{ 343 pcitag_t tag; 344 345 tag = PCITAG_CREATE(node, b, d, f); 346 347 /* 348 * Record the node. This has two effects: 349 * 350 * 1) We don't have to search as far. 351 * 2) pci_bus_devorder will scan the right bus. 352 */ 353 pc->curnode = node; 354 355 /* Enable all the different spaces for this device */ 356 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, 357 PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE| 358 PCI_COMMAND_IO_ENABLE); 359 return (tag); 360} 361 362/* assume we are mapped little-endian/side-effect */ 363pcireg_t 364pci_conf_read(pc, tag, reg) 365 pci_chipset_tag_t pc; 366 pcitag_t tag; 367 int reg; 368{ 369 struct psycho_pbm *pp = pc->cookie; 370 struct psycho_softc *sc = pp->pp_sc; 371 pcireg_t val = (pcireg_t)~0; 372 373 DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx reg %x ", 374 (long)tag, reg)); 375 if (PCITAG_NODE(tag) != -1) { 376 DPRINTF(SPDB_CONF, ("asi=%x addr=%qx (offset=%x) ...", 377 sc->sc_configaddr._asi, 378 (long long)(sc->sc_configaddr._ptr + 379 PCITAG_OFFSET(tag) + reg), 380 (int)PCITAG_OFFSET(tag) + reg)); 381 382 val = bus_space_read_4(sc->sc_configtag, sc->sc_configaddr, 383 PCITAG_OFFSET(tag) + reg); 384 } 385#ifdef DEBUG 386 else DPRINTF(SPDB_CONF, ("pci_conf_read: bogus pcitag %x\n", 387 (int)PCITAG_OFFSET(tag))); 388#endif 389 DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val)); 390 391 return (val); 392} 393 394void 395pci_conf_write(pc, tag, reg, data) 396 pci_chipset_tag_t pc; 397 pcitag_t tag; 398 int reg; 399 pcireg_t data; 400{ 401 struct psycho_pbm *pp = pc->cookie; 402 struct psycho_softc *sc = pp->pp_sc; 403 404 DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ", 405 (long)PCITAG_OFFSET(tag), reg, (int)data)); 406 DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x)\n", 407 sc->sc_configaddr._asi, 408 (long long)(sc->sc_configaddr._ptr + PCITAG_OFFSET(tag) + reg), 409 (int)PCITAG_OFFSET(tag) + reg)); 410 411 /* If we don't know it, just punt it. */ 412 if (PCITAG_NODE(tag) == -1) { 413 DPRINTF(SPDB_CONF, ("pci_conf_write: bad addr")); 414 return; 415 } 416 417 bus_space_write_4(sc->sc_configtag, sc->sc_configaddr, 418 PCITAG_OFFSET(tag) + reg, data); 419} 420 421/* 422 * interrupt mapping foo. 423 * XXX: how does this deal with multiple interrupts for a device? 424 */ 425int 426pci_intr_map(pa, ihp) 427 struct pci_attach_args *pa; 428 pci_intr_handle_t *ihp; 429{ 430 pcitag_t tag = pa->pa_tag; 431 int interrupts; 432 int len, node = PCITAG_NODE(tag); 433 char devtype[30]; 434 435 len = OF_getproplen(node, "interrupts"); 436 if (len < sizeof(interrupts)) { 437 DPRINTF(SPDB_INTMAP, 438 ("pci_intr_map: interrupts len %d too small\n", len)); 439 return (ENODEV); 440 } 441 if (OF_getprop(node, "interrupts", (void *)&interrupts, 442 sizeof(interrupts)) != len) { 443 DPRINTF(SPDB_INTMAP, 444 ("pci_intr_map: could not read interrupts\n")); 445 return (ENODEV); 446 } 447 448 if (OF_mapintr(node, &interrupts, sizeof(interrupts), 449 sizeof(interrupts)) < 0) { 450 printf("OF_mapintr failed\n"); 451 } 452 /* Try to find an IPL for this type of device. */ 453 if (OF_getprop(node, "device_type", &devtype, sizeof(devtype)) > 0) { 454 for (len = 0; intrmap[len].in_class; len++) 455 if (strcmp(intrmap[len].in_class, devtype) == 0) { 456 interrupts |= INTLEVENCODE(intrmap[len].in_lev); 457 break; 458 } 459 } 460 461 /* XXXX -- we use the ino. What if there is a valid IGN? */ 462 *ihp = interrupts; 463 return (0); 464} 465 466const char * 467pci_intr_string(pc, ih) 468 pci_chipset_tag_t pc; 469 pci_intr_handle_t ih; 470{ 471 static char str[16]; 472 473 DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih)); 474 sprintf(str, "ivec %x", ih); 475 DPRINTF(SPDB_INTR, ("; returning %s\n", str)); 476 477 return (str); 478} 479 480const struct evcnt * 481pci_intr_evcnt(pc, ih) 482 pci_chipset_tag_t pc; 483 pci_intr_handle_t ih; 484{ 485 486 /* XXX for now, no evcnt parent reported */ 487 return NULL; 488} 489 490void * 491pci_intr_establish(pc, ih, level, func, arg) 492 pci_chipset_tag_t pc; 493 pci_intr_handle_t ih; 494 int level; 495 int (*func) __P((void *)); 496 void *arg; 497{ 498 void *cookie; 499 struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie; 500 501 DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d", (u_long)ih, level)); 502 cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg); 503 504 DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie)); 505 return (cookie); 506} 507 508void 509pci_intr_disestablish(pc, cookie) 510 pci_chipset_tag_t pc; 511 void *cookie; 512{ 513 514 DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie)); 515 516 /* XXX */ 517 panic("can't disestablish PCI interrupts yet"); 518} 519