pci_machdep.c revision 1.24
1/* $NetBSD: pci_machdep.c,v 1.24 2001/09/15 19:32:14 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 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/iommureg.h> 66#include <sparc64/dev/iommuvar.h> 67#include <sparc64/dev/psychoreg.h> 68#include <sparc64/dev/psychovar.h> 69 70/* this is a base to be copied */ 71struct sparc_pci_chipset _sparc_pci_chipset = { 72 NULL, 73}; 74 75/* 76 * functions provided to the MI code. 77 */ 78 79void 80pci_attach_hook(parent, self, pba) 81 struct device *parent; 82 struct device *self; 83 struct pcibus_attach_args *pba; 84{ 85 /* Don't do nothing */ 86} 87 88int 89pci_bus_maxdevs(pc, busno) 90 pci_chipset_tag_t pc; 91 int busno; 92{ 93 94 return 32; 95} 96 97#ifdef __PCI_BUS_DEVORDER 98int 99pci_bus_devorder(pc, busno, devs) 100 pci_chipset_tag_t pc; 101 int busno; 102 char *devs; 103{ 104 struct ofw_pci_register reg; 105 int node, len, device, i = 0; 106 u_int32_t done = 0; 107#ifdef DEBUG 108 char name[80]; 109#endif 110 111 node = pc->curnode; 112#ifdef DEBUG 113 if (sparc_pci_debug & SPDB_PROBE) { 114 OF_getprop(node, "name", &name, sizeof(name)); 115 printf("pci_bus_devorder: curnode %x %s\n", node, name); 116 } 117#endif 118 /* 119 * Initially, curnode is the root of the pci tree. As we 120 * attach bridges, curnode should be set to that of the bridge. 121 */ 122 for (node = OF_child(node); node; node = OF_peer(node)) { 123 len = OF_getproplen(node, "reg"); 124 if (len < sizeof(reg)) 125 continue; 126 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len) 127 panic("pci_probe_bus: OF_getprop len botch"); 128 129 device = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi); 130 131 if (done & (1 << device)) 132 continue; 133 134 devs[i++] = device; 135 done |= 1 << device; 136#ifdef DEBUG 137 if (sparc_pci_debug & SPDB_PROBE) { 138 OF_getprop(node, "name", &name, sizeof(name)); 139 printf("pci_bus_devorder: adding %x %s\n", node, name); 140 } 141#endif 142 if (i == 32) 143 break; 144 } 145 if (i < 32) 146 devs[i] = -1; 147 148 return i; 149} 150#endif 151 152#ifdef __PCI_DEV_FUNCORDER 153int 154pci_dev_funcorder(pc, busno, device, funcs) 155 pci_chipset_tag_t pc; 156 int busno; 157 int device; 158 char *funcs; 159{ 160 struct ofw_pci_register reg; 161 int node, len, i = 0; 162#ifdef DEBUG 163 char name[80]; 164#endif 165 166 node = pc->curnode; 167#ifdef DEBUG 168 if (sparc_pci_debug & SPDB_PROBE) { 169 OF_getprop(node, "name", &name, sizeof(name)); 170 printf("pci_bus_funcorder: curnode %x %s\n", node, name); 171 } 172#endif 173 /* 174 * Functions are siblings. Presumably we're only called when the 175 * first instance of this device is detected, so we should be able to 176 * get to all the other functions with OF_peer(). But there seems 177 * some issues with this scheme, so we always go to the first node on 178 * this bus segment for a scan. 179 */ 180 for (node = OF_child(OF_parent(node)); node; node = OF_peer(node)) { 181 len = OF_getproplen(node, "reg"); 182 if (len < sizeof(reg)) 183 continue; 184 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len) 185 panic("pci_probe_bus: OF_getprop len botch"); 186 187 if (device != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi)) 188 continue; 189 190 funcs[i++] = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi); 191#ifdef DEBUG 192 if (sparc_pci_debug & SPDB_PROBE) { 193 OF_getprop(node, "name", &name, sizeof(name)); 194 printf("pci_bus_funcorder: adding %x %s\n", node, name); 195 } 196#endif 197 if (i == 8) 198 break; 199 } 200 if (i < 8) 201 funcs[i] = -1; 202 203 return i; 204} 205#endif 206 207pcitag_t 208pci_make_tag(pc, b, d, f) 209 pci_chipset_tag_t pc; 210 int b; 211 int d; 212 int f; 213{ 214 struct ofw_pci_register reg; 215 pcitag_t tag; 216 int busrange[2]; 217 int node, len; 218#ifdef DEBUG 219 char name[80]; 220 bzero(name, sizeof(name)); 221#endif 222 223 /* 224 * Hunt for the node that corresponds to this device 225 * 226 * We could cache this info in an array in the parent 227 * device... except then we have problems with devices 228 * attached below pci-pci bridges, and we would need to 229 * add special code to the pci-pci bridge to cache this 230 * info. 231 */ 232 233 tag = PCITAG_CREATE(-1, b, d, f); 234 node = pc->rootnode; 235 /* 236 * First make sure we're on the right bus. If our parent 237 * has a bus-range property and we're not in the range, 238 * then we're obviously on the wrong bus. So go up one 239 * level. 240 */ 241#ifdef DEBUG 242 if (sparc_pci_debug & SPDB_PROBE) { 243 OF_getprop(node, "name", &name, sizeof(name)); 244 printf("curnode %x %s\n", node, name); 245 } 246#endif 247#if 0 248 while ((OF_getprop(OF_parent(node), "bus-range", (void *)&busrange, 249 sizeof(busrange)) == sizeof(busrange)) && 250 (b < busrange[0] || b > busrange[1])) { 251 /* Out of range, go up one */ 252 node = OF_parent(node); 253#ifdef DEBUG 254 if (sparc_pci_debug & SPDB_PROBE) { 255 OF_getprop(node, "name", &name, sizeof(name)); 256 printf("going up to node %x %s\n", node, name); 257 } 258#endif 259 } 260#endif 261 /* 262 * Now traverse all peers until we find the node or we find 263 * the right bridge. 264 * 265 * XXX We go up one and down one to make sure nobody's missed. 266 * but this should not be necessary. 267 */ 268 for (node = ((node)); node; node = OF_peer(node)) { 269 270#ifdef DEBUG 271 if (sparc_pci_debug & SPDB_PROBE) { 272 OF_getprop(node, "name", &name, sizeof(name)); 273 printf("checking node %x %s\n", node, name); 274 } 275#endif 276 277#if 1 278 /* 279 * Check for PCI-PCI bridges. If the device we want is 280 * in the bus-range for that bridge, work our way down. 281 */ 282 while ((OF_getprop(node, "bus-range", (void *)&busrange, 283 sizeof(busrange)) == sizeof(busrange)) && 284 (b >= busrange[0] && b <= busrange[1])) { 285 /* Go down 1 level */ 286 node = OF_child(node); 287#ifdef DEBUG 288 if (sparc_pci_debug & SPDB_PROBE) { 289 OF_getprop(node, "name", &name, sizeof(name)); 290 printf("going down to node %x %s\n", 291 node, name); 292 } 293#endif 294 } 295#endif 296 /* 297 * We only really need the first `reg' property. 298 * 299 * For simplicity, we'll query the `reg' when we 300 * need it. Otherwise we could malloc() it, but 301 * that gets more complicated. 302 */ 303 len = OF_getproplen(node, "reg"); 304 if (len < sizeof(reg)) 305 continue; 306 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len) 307 panic("pci_probe_bus: OF_getprop len botch"); 308 309 if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi)) 310 continue; 311 if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi)) 312 continue; 313 if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi)) 314 continue; 315 316 /* Got a match */ 317 tag = PCITAG_CREATE(node, b, d, f); 318 319 /* 320 * Record the node. This has two effects: 321 * 322 * 1) We don't have to search as far. 323 * 2) pci_bus_devorder will scan the right bus. 324 */ 325 pc->curnode = node; 326 327 /* Enable all the different spaces for this device */ 328 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, 329 PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE| 330 PCI_COMMAND_IO_ENABLE); 331 DPRINTF(SPDB_PROBE, ("found node %x %s\n", node, name)); 332 return (tag); 333 } 334 /* No device found -- return a dead tag */ 335 return (tag); 336} 337 338/* assume we are mapped little-endian/side-effect */ 339pcireg_t 340pci_conf_read(pc, tag, reg) 341 pci_chipset_tag_t pc; 342 pcitag_t tag; 343 int reg; 344{ 345 struct psycho_pbm *pp = pc->cookie; 346 struct psycho_softc *sc = pp->pp_sc; 347 pcireg_t val = (pcireg_t)~0; 348 349 DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx reg %x ", 350 (long)tag, reg)); 351 if (PCITAG_NODE(tag) != -1) { 352 DPRINTF(SPDB_CONF, ("asi=%x addr=%qx (offset=%x) ...", 353 bus_type_asi[sc->sc_configtag->type], 354 (long long)(sc->sc_configaddr + 355 PCITAG_OFFSET(tag) + reg), 356 (int)PCITAG_OFFSET(tag) + reg)); 357 358 val = bus_space_read_4(sc->sc_configtag, sc->sc_configaddr, 359 PCITAG_OFFSET(tag) + reg); 360 } 361#ifdef DEBUG 362 else DPRINTF(SPDB_CONF, ("pci_conf_read: bogus pcitag %x\n", 363 (int)PCITAG_OFFSET(tag))); 364#endif 365 DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val)); 366 367 return (val); 368} 369 370void 371pci_conf_write(pc, tag, reg, data) 372 pci_chipset_tag_t pc; 373 pcitag_t tag; 374 int reg; 375 pcireg_t data; 376{ 377 struct psycho_pbm *pp = pc->cookie; 378 struct psycho_softc *sc = pp->pp_sc; 379 380 DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ", 381 (long)PCITAG_OFFSET(tag), reg, (int)data)); 382 DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x)\n", 383 bus_type_asi[sc->sc_configtag->type], 384 (long long)(sc->sc_configaddr + PCITAG_OFFSET(tag) + reg), 385 (int)PCITAG_OFFSET(tag) + reg)); 386 387 /* If we don't know it, just punt it. */ 388 if (PCITAG_NODE(tag) == -1) { 389 DPRINTF(SPDB_CONF, ("pci_conf_write: bad addr")); 390 return; 391 } 392 393 bus_space_write_4(sc->sc_configtag, sc->sc_configaddr, 394 PCITAG_OFFSET(tag) + reg, data); 395} 396 397/* 398 * interrupt mapping foo. 399 * XXX: how does this deal with multiple interrupts for a device? 400 */ 401int 402pci_intr_map(pa, ihp) 403 struct pci_attach_args *pa; 404 pci_intr_handle_t *ihp; 405{ 406 pcitag_t tag = pa->pa_tag; 407 int interrupts; 408 int len, node = PCITAG_NODE(tag); 409 char devtype[30]; 410 411 len = OF_getproplen(node, "interrupts"); 412 if (len < sizeof(interrupts)) { 413 DPRINTF(SPDB_INTMAP, 414 ("pci_intr_map: interrupts len %d too small\n", len)); 415 return (ENODEV); 416 } 417 if (OF_getprop(node, "interrupts", (void *)&interrupts, 418 sizeof(interrupts)) != len) { 419 DPRINTF(SPDB_INTMAP, 420 ("pci_intr_map: could not read interrupts\n")); 421 return (ENODEV); 422 } 423 424 if (OF_mapintr(node, &interrupts, sizeof(interrupts), 425 sizeof(interrupts)) < 0) { 426 printf("OF_mapintr failed\n"); 427 } 428 /* Try to find an IPL for this type of device. */ 429 if (OF_getprop(node, "device_type", &devtype, sizeof(devtype)) > 0) { 430 for (len = 0; intrmap[len].in_class; len++) 431 if (strcmp(intrmap[len].in_class, devtype) == 0) { 432 interrupts |= INTLEVENCODE(intrmap[len].in_lev); 433 break; 434 } 435 } 436 437 /* XXXX -- we use the ino. What if there is a valid IGN? */ 438 *ihp = interrupts; 439 return (0); 440} 441 442const char * 443pci_intr_string(pc, ih) 444 pci_chipset_tag_t pc; 445 pci_intr_handle_t ih; 446{ 447 static char str[16]; 448 449 DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih)); 450 sprintf(str, "ivec %x", ih); 451 DPRINTF(SPDB_INTR, ("; returning %s\n", str)); 452 453 return (str); 454} 455 456const struct evcnt * 457pci_intr_evcnt(pc, ih) 458 pci_chipset_tag_t pc; 459 pci_intr_handle_t ih; 460{ 461 462 /* XXX for now, no evcnt parent reported */ 463 return NULL; 464} 465 466void * 467pci_intr_establish(pc, ih, level, func, arg) 468 pci_chipset_tag_t pc; 469 pci_intr_handle_t ih; 470 int level; 471 int (*func) __P((void *)); 472 void *arg; 473{ 474 void *cookie; 475 struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie; 476 477 DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d", (u_long)ih, level)); 478 cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg); 479 480 DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie)); 481 return (cookie); 482} 483 484void 485pci_intr_disestablish(pc, cookie) 486 pci_chipset_tag_t pc; 487 void *cookie; 488{ 489 490 DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie)); 491 492 /* XXX */ 493 panic("can't disestablish PCI interrupts yet"); 494} 495